test: wslist.c File Reference

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

# wslist.c File Reference

`#include "mi.h"`

Go to the source code of this file.

## Defines

#define | MM_SYSTEM_CACHE_THRESHOLD ((1024*1024) / PAGE_SIZE)
#define | MM_RETRY_COUNT 2

## Functions

ULONG | MiDoReplacement (IN PMMSUPPORT WsInfo, IN BOOLEAN MustReplace)
VOID | MiReplaceWorkingSetEntryUsingFaultInfo (IN PMMSUPPORT WsInfo, IN BOOLEAN MustReplace)
VOID | MiCheckWsleHash (IN PMMWSL WorkingSetList)
VOID | MiEliminateWorkingSetEntry (IN ULONG WorkingSetIndex, IN PMMPTE PointerPte, IN PMMPFN Pfn, IN PMMWSLE Wsle)
ULONG | MiAddWorkingSetPage (IN PMMSUPPORT WsInfo)
VOID | MiRemoveWorkingSetPages (IN PMMWSL WorkingSetList, IN PMMSUPPORT WsInfo)
VOID | MiCheckNullIndex (IN PMMWSL WorkingSetList)
VOID | MiDumpWsleInCacheBlock (IN PMMPTE CachePte)
ULONG | MiDumpPteInCacheBlock (IN PMMPTE PointerPte)
WSLE_NUMBER | MiLocateAndReserveWsle (IN PMMSUPPORT WsInfo)
LOGICAL | MmEnforceWorkingSetLimit (IN PMMSUPPORT WsInfo, IN LOGICAL Enable)
ULONG | MiRemovePageFromWorkingSet (IN PMMPTE PointerPte, IN PMMPFN Pfn1, IN PMMSUPPORT WsInfo)
VOID | MiReleaseWsle (IN WSLE_NUMBER WorkingSetIndex, IN PMMSUPPORT WsInfo)
VOID | MiUpdateWsle (IN OUT PWSLE_NUMBER DesiredIndex, IN PVOID VirtualAddress, PMMWSL WorkingSetList, IN PMMPFN Pfn)
ULONG | MiFreeWsle (IN WSLE_NUMBER WorkingSetIndex, IN PMMSUPPORT WsInfo, IN PMMPTE PointerPte)
VOID | MiInitializeWorkingSetList (IN PEPROCESS CurrentProcess)
VOID | MiInitializeSessionWsSupport (VOID)
NTSTATUS | MiSessionInitializeWorkingSetList (VOID)
LOGICAL | MmAssignProcessToJob (IN PEPROCESS Process)
NTSTATUS | MmAdjustWorkingSetSize (IN SIZE_T WorkingSetMinimumInBytes, IN SIZE_T WorkingSetMaximumInBytes, IN ULONG SystemCache)
LOGICAL | MiAddWsleHash (IN PMMSUPPORT WsInfo, IN PMMPTE PointerPte)
VOID | MiGrowWsleHash (IN PMMSUPPORT WsInfo)
ULONG | MiTrimWorkingSet (ULONG Reduction, IN PMMSUPPORT WsInfo, IN ULONG ForcedReductionOrTrimAge)
NTSTATUS | MiEmptyWorkingSet (IN PMMSUPPORT WsInfo, IN LOGICAL WaitOk)

## Variables

ULONG | MmMaximumWorkingSetSize
ULONG | MmFaultsTakenToGoAboveMaxWs = 100
ULONG | MmFaultsTakenToGoAboveMinWs = 16
ULONG | MmSystemCodePage
ULONG | MmSystemCachePage
ULONG | MmPagedPoolPage
ULONG | MmSystemDriverPage
ULONG | MmTransitionSharedPages
ULONG | MmTransitionSharedPagesPeak
LOGICAL | MiTrimRemovalPagesOnly

## Define Documentation

#define MM_RETRY_COUNT 2

| Definition at line 45 of file wslist.c. Referenced by MmAdjustWorkingSetSize().

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

| Definition at line 29 of file wslist.c. Referenced by MiDoReplacement().

## Function Documentation

ULONG MiAddWorkingSetPage | ( | IN PMMSUPPORT | WsInfo | ) |

Definition at line 2824 of file wslist.c.

References ASSERT, _MM_SESSION_SPACE::CommittedPages, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, _MMWSL::HashTableStart, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_EXPANSION_IF_ALPHA, LOCK_PFN, MI_GET_PAGE_COLOR_FROM_PTE, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_SET_PTE_DIRTY, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiChargeCommitmentCantExpand(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiInitializePfn(), MiRemoveZeroPage(), MiSwapWslEntries(), MiUpdateWsle(), MM_BUMP_COUNTER, MM_BUMP_SESS_COUNTER, MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES, MM_DBG_SESSION_WS_PAGE_ALLOC_GROWTH, MM_DEMAND_ZERO_WRITE_PTE, MM_FREE_WSLE_SHIFT, MM_GROW_WSLE_HASH, MM_READWRITE, MM_SYSTEM_WS_LOCK_ASSERT, MM_TRACK_COMMIT, MmAvailablePages, MmPagesAboveWsMinimum, MmResidentAvailablePages, MmSessionSpace, MmSystemCacheWs, _MM_SESSION_SPACE::NonPagablePages, NULL, PAGE_SIZE, PsGetCurrentThread, _MMWSL::Quota, TRUE, _MMPTE::u, _MMPFN::u1, _MMWSLE::u1, UNLOCK_EXPANSION_IF_ALPHA, UNLOCK_PFN, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MiLocateAndReserveWsle(), and MmAdjustWorkingSetSize().

    02830                    :
    02831
    02832     This function grows the working set list above working set
    02833     maximum during working set adjustment.  At most one page
    02834     can be added at a time.
    02835
    02836 Arguments:
    02837
    02838     None.
    02839
    02840 Return Value:
    02841
    02842     Returns FALSE if no working set page could be added.
    02843
    02844 Environment:
    02845
    02846     Kernel mode, APCs disabled, working set mutexes held.
    02847
    02848 --*/
    02849
    02850 {
    02851     ULONG SwapEntry;
    02852     ULONG CurrentEntry;
    02853     PMMWSLE WslEntry;
    02854     ULONG i;
    02855     PMMPTE PointerPte;
    02856     PMMPTE PointerPde;
    02857     PMMPTE Va;
    02858     MMPTE TempPte;
    02859     WSLE_NUMBER NumberOfEntriesMapped;
    02860     PFN_NUMBER WorkingSetPage;
    02861     WSLE_NUMBER WorkingSetIndex;
    02862     PMMWSL WorkingSetList;
    02863     PMMWSLE Wsle;
    02864     PMMPFN Pfn1;
    02865     KIRQL OldIrql;
    02866     LOGICAL PageTablePageAllocated;
    02867
    02868     WorkingSetList = WsInfo->VmWorkingSetList;
    02869     Wsle = WorkingSetList->Wsle;
    02870
    02871 #if DBG
    02872     if (WsInfo == &MmSystemCacheWs) {
    02873         MM_SYSTEM_WS_LOCK_ASSERT();
    02874     }
    02875 #endif //DBG
    02876
    02877     //
    02878     // The maximum size of the working set is being increased, check
    02879     // to ensure the proper number of pages are mapped to cover
    02880     // the complete working set list.
    02881     //
    02882
    02883     PointerPte = MiGetPteAddress (&Wsle[WorkingSetList->LastInitializedWsle]);
    02884
    02885     ASSERT (PointerPte->u.Hard.Valid == 1);
    02886
    02887     PointerPte += 1;
    02888
    02889     Va = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte);
    02890
    02891     if ((PVOID)Va >= WorkingSetList->HashTableStart) {
    02892
    02893         //
    02894         // Adding this entry would overrun the hash table.  The caller
    02895         // must replace instead.
    02896         //
    02897
    02898         WorkingSetList->Quota = WorkingSetList->LastInitializedWsle;
    02899         return FALSE;
    02900     }
    02901
    02902     PageTablePageAllocated = FALSE;
    02903
    02904 #if defined (_WIN64)
    02905     PointerPde = MiGetPteAddress (PointerPte);
    02906     if (PointerPde->u.Hard.Valid == 0) {
    02907
    02908         ASSERT (WsInfo->u.Flags.SessionSpace == 0);
    02909
    02910         //
    02911         // Map in a new working set page.
    02912         //
    02913
    02914         LOCK_PFN (OldIrql);
    02915         if (MmAvailablePages < 21) {
    02916
    02917             //
    02918             // No pages are available, set the quota to the last
    02919             // initialized WSLE and return.
    02920             //
    02921
    02922             WorkingSetList->Quota = WorkingSetList->LastInitializedWsle;
    02923             UNLOCK_PFN (OldIrql);
    02924             return FALSE;
    02925         }
    02926
    02927         PageTablePageAllocated = TRUE;
    02928         WorkingSetPage = MiRemoveZeroPage (MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
    02929         PointerPde->u.Long = MM_DEMAND_ZERO_WRITE_PTE;
    02930         MiInitializePfn (WorkingSetPage, PointerPde, 1);
    02931         UNLOCK_PFN (OldIrql);
    02932
    02933         MI_MAKE_VALID_PTE (TempPte,
    02934                            WorkingSetPage,
    02935                            MM_READWRITE,
    02936                            PointerPde);
    02937
    02938         MI_SET_PTE_DIRTY (TempPte);
    02939         MI_WRITE_VALID_PTE (PointerPde, TempPte);
    02940
    02941         //
    02942         // Further down in this routine (once an actual working set page
    02943         // has been allocated) the quota will be increased by 1 to reflect
    02944         // the working set size entry for the new page table page.
    02945         // The page table page will be put in a working set entry which will
    02946         // be locked into the working set.
    02947         //
    02948     }
    02949 #endif
    02950
    02951     ASSERT (PointerPte->u.Hard.Valid == 0);
    02952
    02953     NumberOfEntriesMapped = (WSLE_NUMBER)(((PMMWSLE)((PCHAR)Va + PAGE_SIZE)) - Wsle);
    02954
    02955     //
    02956     // Map in a new working set page.
    02957     //
    02958
    02959     LOCK_PFN (OldIrql);
    02960     if ((PageTablePageAllocated == FALSE) && (MmAvailablePages < 20)) {
    02961
    02962         //
    02963         // No pages are available, set the quota to the last
    02964         // initialized WSLE and return.
    02965         //
    02966
    02967         WorkingSetList->Quota = WorkingSetList->LastInitializedWsle;
    02968         UNLOCK_PFN (OldIrql);
    02969         return FALSE;
    02970     }
    02971
    02972     WorkingSetPage = MiRemoveZeroPage (MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
    02973     PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE;
    02974     MiInitializePfn (WorkingSetPage, PointerPte, 1);
    02975     UNLOCK_PFN (OldIrql);
    02976
    02977     MI_MAKE_VALID_PTE (TempPte,
    02978                        WorkingSetPage,
    02979                        MM_READWRITE,
    02980                        PointerPte);
    02981
    02982     MI_SET_PTE_DIRTY (TempPte);
    02983     MI_WRITE_VALID_PTE (PointerPte, TempPte);
    02984
    02985     if (WsInfo->u.Flags.SessionSpace == 1) {
    02986         MM_BUMP_SESS_COUNTER (MM_DBG_SESSION_WS_PAGE_ALLOC_GROWTH, 1);
    02987         MmSessionSpace->NonPagablePages += 1;
    02988         MmSessionSpace->CommittedPages += 1;
    02989         MiChargeCommitmentCantExpand (1, TRUE);
    02990         LOCK_PFN (OldIrql);
    02991         MM_BUMP_COUNTER (48, 1);
    02992         MmResidentAvailablePages -= 1;
    02993         UNLOCK_PFN (OldIrql);
    02994         MM_TRACK_COMMIT (MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES, 1);
    02995     }
    02996
    02997     CurrentEntry = WorkingSetList->LastInitializedWsle + 1;
    02998
    02999     ASSERT (NumberOfEntriesMapped > CurrentEntry);
    03000
    03001     WslEntry = &Wsle[CurrentEntry - 1];
    03002
    03003     for (i = CurrentEntry; i < NumberOfEntriesMapped; i += 1) {
    03004
    03005         //
    03006         // Build the free list, note that the first working
    03007         // set entries (CurrentEntry) are not on the free list.
    03008         // These entries are reserved for the pages which
    03009         // map the working set and the page which contains the PDE.
    03010         //
    03011
    03012         WslEntry += 1;
    03013         WslEntry->u1.Long = (i + 1) << MM_FREE_WSLE_SHIFT;
    03014     }
    03015
    03016     WslEntry->u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT;
    03017
    03018     ASSERT (CurrentEntry >= WorkingSetList->FirstDynamic);
    03019
    03020     WorkingSetList->FirstFree = CurrentEntry;
    03021
    03022     WorkingSetList->LastInitializedWsle = (NumberOfEntriesMapped - 1);
    03023
    03024     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    03025             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    03026
    03027     //
    03028     // As we are growing the working set, make sure the quota is
    03029     // above the working set size by adding 1 to the quota.
    03030     //
    03031
    03032     WorkingSetList->Quota += 1;
    03033
    03034     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    03035
    03036     CONSISTENCY_LOCK_PFN (OldIrql);
    03037
    03038     Pfn1->u1.Event = (PVOID)PsGetCurrentThread();
    03039
    03040     CONSISTENCY_UNLOCK_PFN (OldIrql);
    03041
    03042     //
    03043     // Get a working set entry.
    03044     //
    03045
    03046     WsInfo->WorkingSetSize += 1;
    03047
    03048     ASSERT (WorkingSetList->FirstFree != WSLE_NULL_INDEX);
    03049     ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
    03050
    03051     WorkingSetIndex = WorkingSetList->FirstFree;
    03052     WorkingSetList->FirstFree = (WSLE_NUMBER)(Wsle[WorkingSetIndex].u1.Long >> MM_FREE_WSLE_SHIFT);
    03053     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    03054             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    03055
    03056     if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    03057         MmPagesAboveWsMinimum += 1;
    03058     }
    03059     if (WorkingSetIndex > WorkingSetList->LastEntry) {
    03060         WorkingSetList->LastEntry = WorkingSetIndex;
    03061     }
    03062
    03063     MiUpdateWsle (&WorkingSetIndex, Va, WorkingSetList, Pfn1);
    03064
    03065     MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex);
    03066
    03067     //
    03068     // Lock any created page table pages into the working set.
    03069     //
    03070
    03071     if (WorkingSetIndex >= WorkingSetList->FirstDynamic) {
    03072
    03073         SwapEntry = WorkingSetList->FirstDynamic;
    03074
    03075         if (WorkingSetIndex != WorkingSetList->FirstDynamic) {
    03076
    03077             //
    03078             // Swap this entry with the one at first dynamic.
    03079             //
    03080
    03081             MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
    03082         }
    03083
    03084         WorkingSetList->FirstDynamic += 1;
    03085
    03086         Wsle[SwapEntry].u1.e1.LockedInWs = 1;
    03087         ASSERT (Wsle[SwapEntry].u1.e1.Valid == 1);
    03088     }
    03089
    03090 #if defined (_WIN64)
    03091     if (PageTablePageAllocated == TRUE) {
    03092
    03093         //
    03094         // As we are growing the working set, make sure the quota is
    03095         // above the working set size by adding 1 to the quota.
    03096         //
    03097
    03098         WorkingSetList->Quota += 1;
    03099
    03100         Pfn1 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
    03101
    03102         CONSISTENCY_LOCK_PFN (OldIrql);
    03103
    03104         Pfn1->u1.Event = (PVOID)PsGetCurrentThread();
    03105
    03106         CONSISTENCY_UNLOCK_PFN (OldIrql);
    03107
    03108         //
    03109         // Get a working set entry.
    03110         //
    03111
    03112         WsInfo->WorkingSetSize += 1;
    03113
    03114         ASSERT (WorkingSetList->FirstFree != WSLE_NULL_INDEX);
    03115         ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
    03116
    03117         WorkingSetIndex = WorkingSetList->FirstFree;
    03118         WorkingSetList->FirstFree = (WSLE_NUMBER)(Wsle[WorkingSetIndex].u1.Long >> MM_FREE_WSLE_SHIFT);
    03119         ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    03120                 (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    03121
    03122         if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    03123             MmPagesAboveWsMinimum += 1;
    03124         }
    03125         if (WorkingSetIndex > WorkingSetList->LastEntry) {
    03126             WorkingSetList->LastEntry = WorkingSetIndex;
    03127         }
    03128
    03129         MiUpdateWsle (&WorkingSetIndex, PointerPte, WorkingSetList, Pfn1);
    03130
    03131         MI_SET_PTE_IN_WORKING_SET (PointerPde, WorkingSetIndex);
    03132
    03133         //
    03134         // Lock the created page table page into the working set.
    03135         //
    03136
    03137         if (WorkingSetIndex >= WorkingSetList->FirstDynamic) {
    03138
    03139             SwapEntry = WorkingSetList->FirstDynamic;
    03140
    03141             if (WorkingSetIndex != WorkingSetList->FirstDynamic) {
    03142
    03143                 //
    03144                 // Swap this entry with the one at first dynamic.
    03145                 //
    03146
    03147                 MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
    03148             }
    03149
    03150             WorkingSetList->FirstDynamic += 1;
    03151
    03152             Wsle[SwapEntry].u1.e1.LockedInWs = 1;
    03153             ASSERT (Wsle[SwapEntry].u1.e1.Valid == 1);
    03154         }
    03155     }
    03156 #endif
    03157
    03158     ASSERT ((MiGetPteAddress(&Wsle[WorkingSetList->LastInitializedWsle]))->u.Hard.Valid == 1);
    03159
    03160     if ((WorkingSetList->HashTable == NULL) &&
    03161         (MmAvailablePages > 20)) {
    03162
    03163         //
    03164         // Add a hash table to support shared pages in the working set to
    03165         // eliminate costly lookups.
    03166         //
    03167
    03168         LOCK_EXPANSION_IF_ALPHA (OldIrql);
    03169         ASSERT (WsInfo->AllowWorkingSetAdjustment != FALSE);
    03170         WsInfo->AllowWorkingSetAdjustment = MM_GROW_WSLE_HASH;
    03171         UNLOCK_EXPANSION_IF_ALPHA (OldIrql);
    03172     }
    03173
    03174     ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->Quota);
    03175     return TRUE;
    03176 }

LOGICAL MiAddWsleHash | ( | IN PMMSUPPORT | WsInfo,
|  | IN PMMPTE | PointerPte
| ) |

Definition at line 3179 of file wslist.c.

References ASSERT, _MM_SESSION_SPACE::CommittedPages, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, _MMWSLE::e1, FALSE, _MMWSL::FirstDynamic, LOCK_PFN, MI_GET_PAGE_COLOR_FROM_PTE, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_SET_PTE_DIRTY, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiChargeCommitmentCantExpand(), MiGetVirtualAddressMappedByPte, MiInitializePfn(), MiLocateAndReserveWsle(), MiRemoveZeroPage(), MiSwapWslEntries(), MiUpdateWsle(), MM_BUMP_SESS_COUNTER, MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES, MM_DBG_SESSION_WS_HASHPAGE_ALLOC, MM_DEMAND_ZERO_WRITE_PTE, MM_READWRITE, MM_TRACK_COMMIT, MmAvailablePages, MmSessionSpace, _MM_SESSION_SPACE::NonPagablePages, PsGetCurrentThread, TRUE, _MMWSLE::u1, _MMPFN::u1, UNLOCK_PFN, _MMWSLENTRY::Valid, _MMWSL::Wsle, and WSLE_NUMBER.

Referenced by MiGrowWsleHash().

    03186                    :
    03187
    03188     This function adds a page directory, page table or actual mapping page
    03189     for hash table creation (or expansion) for the current process.
    03190
    03191 Arguments:
    03192
    03193     WsInfo - Supplies a pointer to the working set info block for the
    03194              process (or system cache).
    03195
    03196     PointerPte - Supplies a pointer to the PTE to be filled.
    03197
    03198 Return Value:
    03199
    03200     None.
    03201
    03202 Environment:
    03203
    03204     Kernel mode, APCs disabled, working set lock held.
    03205
    03206 --*/
    03207 {
    03208     KIRQL OldIrql;
    03209     PMMPFN Pfn1;
    03210     ULONG SwapEntry;
    03211     MMPTE TempPte;
    03212     PVOID Va;
    03213     PMMWSLE Wsle;
    03214     PFN_NUMBER WorkingSetPage;
    03215     WSLE_NUMBER WorkingSetIndex;
    03216     PMMWSL WorkingSetList;
    03217
    03218     WorkingSetList = WsInfo->VmWorkingSetList;
    03219     Wsle = WorkingSetList->Wsle;
    03220
    03221     ASSERT (PointerPte->u.Hard.Valid == 0);
    03222
    03223     LOCK_PFN (OldIrql);
    03224
    03225     if (MmAvailablePages < 10) {
    03226         UNLOCK_PFN (OldIrql);
    03227         return FALSE;
    03228     }
    03229
    03230     WorkingSetPage = MiRemoveZeroPage (
    03231                                 MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
    03232
    03233     PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE;
    03234     MiInitializePfn (WorkingSetPage, PointerPte, 1);
    03235
    03236     MI_MAKE_VALID_PTE (TempPte,
    03237                        WorkingSetPage,
    03238                        MM_READWRITE,
    03239                        PointerPte );
    03240
    03241     MI_SET_PTE_DIRTY (TempPte);
    03242     MI_WRITE_VALID_PTE (PointerPte, TempPte);
    03243
    03244     UNLOCK_PFN (OldIrql);
    03245
    03246     //
    03247     // As we are growing the working set, we know that quota
    03248     // is above the current working set size.  Just take the
    03249     // next free WSLE from the list and use it.
    03250     //
    03251
    03252     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    03253
    03254     CONSISTENCY_LOCK_PFN (OldIrql);
    03255
    03256     Pfn1->u1.Event = (PVOID)PsGetCurrentThread();
    03257
    03258     CONSISTENCY_UNLOCK_PFN (OldIrql);
    03259
    03260     Va = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte);
    03261
    03262     WorkingSetIndex = MiLocateAndReserveWsle (WsInfo);
    03263     MiUpdateWsle (&WorkingSetIndex, Va, WorkingSetList, Pfn1);
    03264     MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex);
    03265
    03266     //
    03267     // Lock any created page table pages into the working set.
    03268     //
    03269
    03270     if (WorkingSetIndex >= WorkingSetList->FirstDynamic) {
    03271
    03272         SwapEntry = WorkingSetList->FirstDynamic;
    03273
    03274         if (WorkingSetIndex != WorkingSetList->FirstDynamic) {
    03275
    03276             //
    03277             // Swap this entry with the one at first dynamic.
    03278             //
    03279
    03280             MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
    03281         }
    03282
    03283         WorkingSetList->FirstDynamic += 1;
    03284
    03285         Wsle[SwapEntry].u1.e1.LockedInWs = 1;
    03286         ASSERT (Wsle[SwapEntry].u1.e1.Valid == 1);
    03287     }
    03288
    03289     if (WsInfo->u.Flags.SessionSpace == 1) {
    03290         MM_BUMP_SESS_COUNTER (MM_DBG_SESSION_WS_HASHPAGE_ALLOC, 1);
    03291         MmSessionSpace->NonPagablePages += 1;
    03292         MmSessionSpace->CommittedPages += 1;
    03293         MiChargeCommitmentCantExpand (1, TRUE);
    03294         MM_TRACK_COMMIT (MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES, 1);
    03295     }
    03296     return TRUE;
    03297 }

VOID MiCheckNullIndex | ( | IN PMMWSL | WorkingSetList | ) |

| Referenced by MiRemoveWorkingSetPages().

VOID MiCheckWsleHash | ( | IN PMMWSL | WorkingSetList | ) |

ULONG MiDoReplacement | ( | IN PMMSUPPORT | WsInfo,
|  | IN BOOLEAN | MustReplace
| ) |

Definition at line 254 of file wslist.c.

References ASSERT, FALSE, KeQuerySystemTime(), LOCK_EXPANSION_IF_ALPHA, MEMORY_PRIORITY_FOREGROUND, MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT, MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT, MI_PASS0_TRIM_AGE, MI_PASS4_TRIM_AGE, MI_SESSION_MAXIMUM_WORKING_SET, MI_WS_GROWING_TOO_FAST, MiReplaceWorkingSetEntryUsingFaultInfo(), MiTrimWorkingSet(), MM_FORCE_TRIM, MM_MAXIMUM_WORKING_SET, MM_NO_WS_EXPANSION, MM_SYSTEM_CACHE_THRESHOLD, MM_SYSTEM_WS_LOCK_ASSERT, MmAvailablePages, MmFaultsTakenToGoAboveMinWs, MmMoreThanEnoughFreePages, MmSystemCacheWs, MmWorkingSetSizeExpansion, MmWorkingSetSizeIncrement, MmWsAdjustThreshold, MmWsExpandThreshold, NULL, _MMWSL::Quota, TRUE, and UNLOCK_EXPANSION_IF_ALPHA.

Referenced by MiLocateAndReserveWsle().

    00261                    :
    00262
    00263     This function determines whether the working set should be
    00264     grown or if a page should be replaced.  Replacement is
    00265     done here if deemed necessary.
    00266
    00267 Arguments:
    00268
    00269     WsInfo - Supplies the working set information structure to replace within.
    00270
    00271     MustReplace - Supplies TRUE if replacement must succeed.
    00272
    00273 Return Value:
    00274
    00275     Quota increment if growth is necessary.
    00276
    00277 Environment:
    00278
    00279     Kernel mode, APCs disabled, working set lock.  PFN lock NOT held.
    00280
    00281 --*/
    00282
    00283 {
    00284     PMMWSL WorkingSetList;
    00285     ULONG CurrentSize;
    00286     LARGE_INTEGER CurrentTime;
    00287 #if defined(_ALPHA_) && !defined(_AXP64_)
    00288     KIRQL OldIrql;
    00289 #endif
    00290     ULONG QuotaIncrement;
    00291     PFN_NUMBER AvailablePageThreshold;
    00292 #ifdef _MI_USE_CLAIMS_
    00293     PEPROCESS ProcessToTrim;
    00294     ULONG Dummy1;
    00295     ULONG Dummy2;
    00296     ULONG Trim;
    00297     ULONG TrimAge;
    00298 #endif
    00299
    00300     WorkingSetList = WsInfo->VmWorkingSetList;
    00301
    00302     if (WsInfo == &MmSystemCacheWs) {
    00303         MM_SYSTEM_WS_LOCK_ASSERT();
    00304         AvailablePageThreshold = MM_SYSTEM_CACHE_THRESHOLD;
    00305     }
    00306
    00307     //
    00308     // Determine the number of pages that need to be available to
    00309     // grow the working set and how much the quota should be
    00310     // boosted if the working set grows over it.
    00311     //
    00312     // If below the Minimum use the defaults.
    00313     //
    00314
    00315 recheck:
    00316
    00317     AvailablePageThreshold = 0;
    00318     QuotaIncrement = 1;
    00319
    00320     if (WsInfo->WorkingSetSize >= WsInfo->MinimumWorkingSetSize) {
    00321
    00322         if (WsInfo->AllowWorkingSetAdjustment == MM_FORCE_TRIM) {
    00323
    00324             //
    00325             // The working set manager cannot attach to this process
    00326             // to trim it.  Force a trim now and update the working
    00327             // set manager's fields properly to indicate a trim occurred.
    00328             //
    00329
    00330 #ifdef _MI_USE_CLAIMS_
    00331
    00332             Trim = WsInfo->Claim >>
    00333                             ((WsInfo->MemoryPriority == MEMORY_PRIORITY_FOREGROUND)
    00334                                 ? MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT
    00335                                 : MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT);
    00336
    00337             if (WsInfo == &MmSystemCacheWs) {
    00338                 ProcessToTrim = NULL;
    00339             }
    00340             else if (WsInfo->u.Flags.SessionSpace == 0) {
    00341                 ProcessToTrim = CONTAINING_RECORD(WsInfo, EPROCESS, Vm);
    00342             }
    00343             else {
    00344                 ProcessToTrim = NULL;       // Hydra session.
    00345             }
    00346
    00347             if (MmAvailablePages < 100) {
    00348                 if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    00349                     Trim = (WsInfo->WorkingSetSize - WsInfo->MinimumWorkingSetSize) >> 2;
    00350                 }
    00351                 TrimAge = MI_PASS4_TRIM_AGE;
    00352             }
    00353             else {
    00354                 TrimAge = MI_PASS0_TRIM_AGE;
    00355             }
    00356
    00357             MiTrimWorkingSet (Trim, WsInfo, TrimAge);
    00358
    00359             MiAgeAndEstimateAvailableInWorkingSet (WsInfo,
    00360                                                    TRUE,
    00361                                                    &Dummy1,
    00362                                                    &Dummy2
    00363                                                    );
    00364 #else
    00365             MiTrimWorkingSet(20, WsInfo, FALSE);
    00366 #endif
    00367
    00368             KeQuerySystemTime (&CurrentTime);
    00369             WsInfo->LastTrimTime = CurrentTime;
    00370             WsInfo->LastTrimFaultCount = WsInfo->PageFaultCount;
    00371 #if defined(_ALPHA_) && !defined(_AXP64_)
    00372             LOCK_EXPANSION_IF_ALPHA (OldIrql);
    00373 #endif
    00374             WsInfo->AllowWorkingSetAdjustment = TRUE;
    00375 #if defined(_ALPHA_) && !defined(_AXP64_)
    00376             UNLOCK_EXPANSION_IF_ALPHA (OldIrql);
    00377 #endif
    00378
    00379             //
    00380             // Set the quota to the current size.
    00381             //
    00382
    00383             WorkingSetList->Quota = WsInfo->WorkingSetSize;
    00384             if (WorkingSetList->Quota < WsInfo->MinimumWorkingSetSize) {
    00385                 WorkingSetList->Quota = WsInfo->MinimumWorkingSetSize;
    00386             }
    00387
    00388             goto recheck;
    00389         }
    00390
    00391         CurrentSize = WsInfo->WorkingSetSize;
    00392         ASSERT (CurrentSize <= (WorkingSetList->LastInitializedWsle + 1));
    00393
    00394         if ((WsInfo->u.Flags.WorkingSetHard) && (CurrentSize >= WsInfo->MaximumWorkingSetSize)) {
    00395
    00396             //
    00397             // This is an enforced working set maximum triggering a replace.
    00398             //
    00399
    00400 #ifdef _MI_USE_CLAIMS_
    00401             MiReplaceWorkingSetEntryUsingClaim (WsInfo, MustReplace);
    00402 #else
    00403             MiReplaceWorkingSetEntryUsingFaultInfo (WsInfo, MustReplace);
    00404 #endif
    00405             return 0;
    00406         }
    00407
    00408 #ifdef _MI_USE_CLAIMS_
    00409
    00410         //
    00411         // If using claims, don't grow if
    00412         //      - we're over the max
    00413         //      - there aren't any pages to take
    00414         //      - or if we are growing too much in this
    00415         //        time interval and there isn't much
    00416         //        memory available
    00417         //
    00418
    00419         if (CurrentSize > MM_MAXIMUM_WORKING_SET || MmAvailablePages == 0 || MustReplace == TRUE) {
    00420
    00421             //
    00422             // Can't grow this one.
    00423             //
    00424
    00425             AvailablePageThreshold = 0xffffffff;
    00426             MiReplacing = TRUE;
    00427         }
    00428 #if defined (_X86PAE_)
    00429         else if ((WsInfo->u.Flags.SessionSpace == 1) && (CurrentSize > MI_SESSION_MAXIMUM_WORKING_SET)) {
    00430
    00431             //
    00432             // Can't grow this one.
    00433             //
    00434
    00435             AvailablePageThreshold = 0xffffffff;
    00436             MiReplacing = TRUE;
    00437         }
    00438 #endif
    00439         else if (MmAvailablePages < 10000 && MI_WS_GROWING_TOO_FAST(WsInfo)) {
    00440
    00441             //
    00442             // Can't grow this one either.
    00443             //
    00444
    00445             AvailablePageThreshold = 0xffffffff;
    00446             MiReplacing = TRUE;
    00447         }
    00448 #else
    00449         //
    00450         // Not using claims, base the growth on how much faulting
    00451         // the process is doing.
    00452         //
    00453
    00454         if (MustReplace == TRUE) {
    00455             AvailablePageThreshold = 0xffffffff;
    00456         }
    00457         if (CurrentSize < WorkingSetList->Quota) {
    00458
    00459             //
    00460             // Working set is below quota, allow it to grow with few pages
    00461             // available.
    00462             //
    00463
    00464             AvailablePageThreshold = 10;
    00465             QuotaIncrement = 1;
    00466         } else if (CurrentSize < WsInfo->MaximumWorkingSetSize) {
    00467
    00468             //
    00469             // Working set is between min and max.  Allow it to grow if enough
    00470             // faults have been taken since last adjustment.
    00471             //
    00472
    00473             if ((WsInfo->PageFaultCount - WsInfo->LastTrimFaultCount) <
    00474                     MmFaultsTakenToGoAboveMinWs) {
    00475                 AvailablePageThreshold = MmMoreThanEnoughFreePages + 200;
    00476                 if (WsInfo->MemoryPriority == MEMORY_PRIORITY_FOREGROUND) {
    00477                     AvailablePageThreshold -= 250;
    00478                 }
    00479             } else {
    00480                 AvailablePageThreshold = MmWsAdjustThreshold;
    00481             }
    00482             QuotaIncrement = (ULONG)MmWorkingSetSizeIncrement;
    00483         } else {
    00484
    00485             //
    00486             // Working set is above max.
    00487             //
    00488
    00489             if ((WsInfo->PageFaultCount - WsInfo->LastTrimFaultCount) <
    00490                     (CurrentSize >> 3))
    00491             {
    00492                 AvailablePageThreshold = MmMoreThanEnoughFreePages + 200;
    00493                 if (WsInfo->MemoryPriority == MEMORY_PRIORITY_FOREGROUND) {
    00494                     AvailablePageThreshold -= 250;
    00495                 }
    00496             } else {
    00497                 AvailablePageThreshold += MmWsExpandThreshold;
    00498             }
    00499             QuotaIncrement = (ULONG)MmWorkingSetSizeExpansion;
    00500
    00501             if (CurrentSize > MM_MAXIMUM_WORKING_SET) {
    00502                 AvailablePageThreshold = 0xffffffff;
    00503                 QuotaIncrement = 1;
    00504             }
    00505 #if defined (_X86PAE_)
    00506             else if ((WsInfo->u.Flags.SessionSpace == 1) && (CurrentSize > MI_SESSION_MAXIMUM_WORKING_SET)) {
    00507                 AvailablePageThreshold = 0xffffffff;
    00508                 QuotaIncrement = 1;
    00509             }
    00510 #endif
    00511         }
    00512 #endif
    00513     }
    00514
    00515     //
    00516     // If there isn't enough memory to allow growth, find a good page
    00517     // to remove and remove it.
    00518     //
    00519
    00520     if (WsInfo->AddressSpaceBeingDeleted == 0 && AvailablePageThreshold != 0) {
    00521         if ((MmAvailablePages <= AvailablePageThreshold) ||
    00522              (WsInfo->WorkingSetExpansionLinks.Flink == MM_NO_WS_EXPANSION)) {
    00523
    00524 #ifdef _MI_USE_CLAIMS_
    00525             MiReplaceWorkingSetEntryUsingClaim (WsInfo, MustReplace);
    00526 #else
    00527             MiReplaceWorkingSetEntryUsingFaultInfo (WsInfo, MustReplace);
    00528 #endif
    00529         }
    00530         else {
    00531             WsInfo->GrowthSinceLastEstimate += 1;
    00532         }
    00533     }
    00534     else {
    00535         WsInfo->GrowthSinceLastEstimate += 1;
    00536     }
    00537
    00538     return QuotaIncrement;
    00539 }

ULONG MiDumpPteInCacheBlock | ( | IN PMMPTE | PointerPte | ) |

VOID MiDumpWsleInCacheBlock | ( | IN PMMPTE | CachePte | ) |

| Referenced by MiFreeWsle().

VOID MiEliminateWorkingSetEntry | ( | IN ULONG | WorkingSetIndex,
|  | IN PMMPTE | PointerPte,
|  | IN PMMPFN | Pfn,
|  | IN PMMWSLE | Wsle
| ) |

Definition at line 3974 of file wslist.c.

References ASSERT, FALSE, KeBugCheckEx(), KeFlushSingleTb(), MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_FLUSH_SINGLE_SESSION_TB, MI_GET_PAGE_FRAME_FROM_PTE, MI_GET_PROTECTION_FROM_WSLE, MI_IS_PTE_DIRTY, MI_IS_SESSION_IMAGE_ADDRESS, MI_MAKE_VALID_PTE_TRANSITION, MI_MAKING_VALID_PTE_INVALID, MI_PTE_LOOKUP_NEEDED, MI_ZERO_WSINDEX, MiActiveWriteWatch, MiCaptureWriteWatchDirtyBit(), MiCheckPdeForPagedPool(), MiDecrementShareAndValidCount, MiDecrementShareCount(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiProtoAddressForPte, MM_PFN_LOCK_ASSERT, MmSystemCacheWsle, MmWsle, NT_SUCCESS, PsGetCurrentProcess, TRUE, _MMSUPPORT::u, _MMPTE::u, and _EPROCESS::Vm.

Referenced by MiFreeWsle(), and MiRemovePageFromWorkingSet().

    03983                    :
    03984
    03985     This routine removes the specified working set list entry
    03986     from the working set, flushes the TB for the page, decrements
    03987     the share count for the physical page, and, if necessary turns
    03988     the PTE into a transition PTE.
    03989
    03990 Arguments:
    03991
    03992     WorkingSetIndex - Supplies the working set index to remove.
    03993
    03994     PointerPte - Supplies a pointer to the PTE corresponding to the virtual
    03995                  address in the working set.
    03996
    03997     Pfn - Supplies a pointer to the PFN element corresponding to the PTE.
    03998
    03999     Wsle - Supplies a pointer to the first working set list entry for this
    04000            working set.
    04001
    04002 Return Value:
    04003
    04004     None.
    04005
    04006 Environment:
    04007
    04008     Kernel mode, Working set lock and PFN lock held, APCs disabled.
    04009
    04010 --*/
    04011
    04012 {
    04013     PMMPTE ContainingPageTablePage;
    04014     MMPTE TempPte;
    04015     MMPTE PreviousPte;
    04016     PFN_NUMBER PageFrameIndex;
    04017     PEPROCESS Process;
    04018     PVOID VirtualAddress;
    04019
    04020     //
    04021     // Remove the page from the working set.
    04022     //
    04023
    04024     MM_PFN_LOCK_ASSERT ();
    04025
    04026     TempPte = *PointerPte;
    04027     PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&TempPte);
    04028
    04029 #ifdef _X86_
    04030 #if DBG
    04031 #if !defined(NT_UP)
    04032     if (TempPte.u.Hard.Writable == 1) {
    04033         ASSERT (TempPte.u.Hard.Dirty == 1);
    04034     }
    04035     ASSERT (TempPte.u.Hard.Accessed == 1);
    04036 #endif //NTUP
    04037 #endif //DBG
    04038 #endif //X86
    04039
    04040     MI_MAKING_VALID_PTE_INVALID (FALSE);
    04041
    04042     if (Pfn->u3.e1.PrototypePte) {
    04043
    04044         //
    04045         // This is a prototype PTE.  The PFN database does not contain
    04046         // the contents of this PTE it contains the contents of the
    04047         // prototype PTE.  This PTE must be reconstructed to contain
    04048         // a pointer to the prototype PTE.
    04049         //
    04050         // The working set list entry contains information about
    04051         // how to reconstruct the PTE.
    04052         //
    04053
    04054         if (Wsle[WorkingSetIndex].u1.e1.SameProtectAsProto == 0) {
    04055
    04056             //
    04057             // The protection for the prototype PTE is in the
    04058             // WSLE.
    04059             //
    04060
    04061             ASSERT (Wsle[WorkingSetIndex].u1.e1.Protection != 0);
    04062
    04063             if (!MI_IS_SESSION_IMAGE_ADDRESS (MiGetVirtualAddressMappedByPte(PointerPte))) {
    04064                 TempPte.u.Long = 0;
    04065                 TempPte.u.Soft.Protection =
    04066                     MI_GET_PROTECTION_FROM_WSLE (&Wsle[WorkingSetIndex]);
    04067                 TempPte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED;
    04068             }
    04069             else {
    04070
    04071                 //
    04072                 // The session PTE protection must be carefully preserved.
    04073                 //
    04074
    04075                 TempPte.u.Long = MiProtoAddressForPte (Pfn->PteAddress);
    04076             }
    04077         } else {
    04078
    04079             //
    04080             // The protection is in the prototype PTE.
    04081             //
    04082
    04083             TempPte.u.Long = MiProtoAddressForPte (Pfn->PteAddress);
    04084
    04085             if (MI_IS_SESSION_IMAGE_ADDRESS (MiGetVirtualAddressMappedByPte(PointerPte))) {
    04086
    04087                 //
    04088                 // The session PTE protection must be carefully preserved.
    04089                 //
    04090
    04091                 TempPte.u.Proto.ReadOnly = 1;
    04092             }
    04093         }
    04094
    04095         TempPte.u.Proto.Prototype = 1;
    04096
    04097         //
    04098         // Decrement the share count of the containing page table
    04099         // page as the PTE for the removed page is no longer valid
    04100         // or in transition
    04101         //
    04102
    04103         ContainingPageTablePage = MiGetPteAddress (PointerPte);
    04104 #if defined (_WIN64)
    04105         ASSERT (ContainingPageTablePage->u.Hard.Valid == 1);
    04106 #else
    04107         if (ContainingPageTablePage->u.Hard.Valid == 0) {
    04108             if (!NT_SUCCESS(MiCheckPdeForPagedPool (PointerPte))) {
    04109                 KeBugCheckEx (MEMORY_MANAGEMENT,
    04110                               0x61940,
    04111                               (ULONG_PTR)PointerPte,
    04112                               (ULONG_PTR)ContainingPageTablePage->u.Long,
    04113                               (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPte));
    04114             }
    04115         }
    04116 #endif
    04117         MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (ContainingPageTablePage));
    04118
    04119     } else {
    04120
    04121         //
    04122         // This is a private page, make it transition.
    04123         //
    04124
    04125         //
    04126         // Assert that the share count is 1 for all user mode pages.
    04127         //
    04128
    04129         ASSERT ((Pfn->u2.ShareCount == 1) ||
    04130                 (Wsle[WorkingSetIndex].u1.VirtualAddress >
    04131                         (PVOID)MM_HIGHEST_USER_ADDRESS));
    04132
    04133         //
    04134         // Set the working set index to zero.  This allows page table
    04135         // pages to be brought back in with the proper WSINDEX.
    04136         //
    04137
    04138         ASSERT (Pfn->u1.WsIndex != 0);
    04139         MI_ZERO_WSINDEX (Pfn);
    04140         MI_MAKE_VALID_PTE_TRANSITION (TempPte,
    04141                                       Pfn->OriginalPte.u.Soft.Protection);
    04142     }
    04143
    04144     if (Wsle == MmWsle) {
    04145         PreviousPte.u.Flush = KeFlushSingleTb (
    04146                                     Wsle[WorkingSetIndex].u1.VirtualAddress,
    04147                                     TRUE,
    04148                                     FALSE,
    04149                                     (PHARDWARE_PTE)PointerPte,
    04150                                     TempPte.u.Flush);
    04151     }
    04152     else if (Wsle == MmSystemCacheWsle) {
    04153
    04154         //
    04155         // Must be the system cache.
    04156         //
    04157
    04158         PreviousPte.u.Flush = KeFlushSingleTb (
    04159                                     Wsle[WorkingSetIndex].u1.VirtualAddress,
    04160                                     TRUE,
    04161                                     TRUE,
    04162                                     (PHARDWARE_PTE)PointerPte,
    04163                                     TempPte.u.Flush);
    04164     }
    04165     else {
    04166
    04167         //
    04168         // Must be a session space.
    04169         //
    04170
    04171         MI_FLUSH_SINGLE_SESSION_TB (Wsle[WorkingSetIndex].u1.VirtualAddress,
    04172                                     TRUE,
    04173                                     FALSE,
    04174                                     (PHARDWARE_PTE)PointerPte,
    04175                                     TempPte.u.Flush,
    04176                                     PreviousPte);
    04177     }
    04178
    04179     ASSERT (PreviousPte.u.Hard.Valid == 1);
    04180
    04181     //
    04182     // A page is being removed from the working set, on certain
    04183     // hardware the dirty bit should be ORed into the modify bit in
    04184     // the PFN element.
    04185     //
    04186
    04187     MI_CAPTURE_DIRTY_BIT_TO_PFN (&PreviousPte, Pfn);
    04188
    04189     //
    04190     // If the PTE indicates the page has been modified (this is different
    04191     // from the PFN indicating this), then ripple it back to the write watch
    04192     // bitmap now since we are still in the correct process context.
    04193     //
    04194
    04195     if (MiActiveWriteWatch != 0) {
    04196         if ((Pfn->u3.e1.PrototypePte == 0) &&
    04197             (MI_IS_PTE_DIRTY(PreviousPte))) {
    04198
    04199             Process = PsGetCurrentProcess();
    04200
    04201             if (Process->Vm.u.Flags.WriteWatch == 1) {
    04202
    04203                 //
    04204                 // This process has (or had) write watch VADs.  Search now
    04205                 // for a write watch region encapsulating the PTE being
    04206                 // invalidated.
    04207                 //
    04208
    04209                 VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte);
    04210                 MiCaptureWriteWatchDirtyBit (Process, VirtualAddress);
    04211             }
    04212         }
    04213     }
    04214
    04215     //
    04216     // Flush the translation buffer and decrement the number of valid
    04217     // PTEs within the containing page table page.  Note that for a
    04218     // private page, the page table page is still needed because the
    04219     // page is in transition.
    04220     //
    04221
    04222     MiDecrementShareCount (PageFrameIndex);
    04223
    04224     return;
    04225 }

NTSTATUS MiEmptyWorkingSet | ( | IN PMMSUPPORT | WsInfo,
|  | IN LOGICAL | WaitOk
| ) |

Definition at line 4726 of file wslist.c.

References _EPROCESS::AddressSpaceDeleted, APC_LEVEL, ASSERT, Count, ExTryToAcquireResourceExclusiveLite(), FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, KeDelayExecutionThread(), KeLowerIrql(), KeRaiseIrql(), KernelMode, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_SESSION_SPACE_WS, LOCK_SYSTEM_WS, LOCK_WS, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MiFreeWsle(), MiGetPteAddress, MiHydra, MiRemoveWorkingSetPages(), MiTrimRemovalPagesOnly, MM_FREE_WSLE_SHIFT, MM_SET_SESSION_RESOURCE_OWNER, MmShortTime, MmSystemCacheWs, MmSystemLockOwner, MmSystemWsLock, _MMWSL::NextSlot, NTSTATUS(), PERFINFO_GET_PAGE_INFO, PERFINFO_LOG_WS_REMOVAL, PERFINFO_PAGE_INFO_DECL, PsGetCurrentProcess, PsGetCurrentThread, _MMPFN::PteFrame, _MMWSL::Quota, Status, TRUE, _MMSUPPORT::u, _MMWSLE::u1, _MMPFN::u3, UNLOCK_SESSION_SPACE_WS, UNLOCK_SYSTEM_WS, UNLOCK_WS, _MMWSLE::VirtualAddress, _EPROCESS::WorkingSetLock, _MMWSL::Wsle, WSLE_NULL_INDEX, and _MM_SESSION_SPACE::WsLock.

Referenced by MiEmptyAllWorkingSetsWorker(), MmAdjustWorkingSetSize(), and MmTrimAllSystemPagableMemory().

    04733                    :
    04734
    04735     This routine frees all pages from the working set.
    04736
    04737 Arguments:
    04738
    04739     WsInfo - Supplies the working set information entry to trim.
    04740
    04741     WaitOk - Supplies TRUE if the caller can wait, FALSE if not.
    04742
    04743 Return Value:
    04744
    04745     Status of operation.
    04746
    04747 Environment:
    04748
    04749     Kernel mode. No locks.  For session operations, the caller is responsible
    04750     for attaching into the proper session.
    04751
    04752 --*/
    04753
    04754 {
    04755     PEPROCESS Process;
    04756     KIRQL OldIrql;
    04757     PMMPTE PointerPte;
    04758     ULONG Entry;
    04759     ULONG Count;
    04760     ULONG LastFreed;
    04761     PMMWSL WorkingSetList;
    04762     PMMWSLE Wsle;
    04763     PMMPFN Pfn1;
    04764     PFN_NUMBER PageFrameIndex;
    04765     ULONG Last;
    04766     NTSTATUS Status;
    04767     PMM_SESSION_SPACE SessionSpace;
    04768
    04769     if (WsInfo == &MmSystemCacheWs) {
    04770         if (WaitOk == TRUE) {
    04771             LOCK_SYSTEM_WS (OldIrql);
    04772         }
    04773         else {
    04774             KeRaiseIrql (APC_LEVEL, &OldIrql);
    04775             if (!ExTryToAcquireResourceExclusiveLite (&MmSystemWsLock)) {
    04776
    04777                 //
    04778                 // System working set lock was not granted, don't trim
    04779                 // the system cache.
    04780                 //
    04781
    04782                 KeLowerIrql (OldIrql);
    04783                 return STATUS_SUCCESS;
    04784             }
    04785
    04786             MmSystemLockOwner = PsGetCurrentThread();
    04787         }
    04788     }
    04789     else if (WsInfo->u.Flags.SessionSpace == 0) {
    04790         Process = PsGetCurrentProcess ();
    04791         if (WaitOk == TRUE) {
    04792             LOCK_WS (Process);
    04793         }
    04794         else {
    04795             Count = 0;
    04796             do {
    04797                 if (ExTryToAcquireFastMutex(&Process->WorkingSetLock) != FALSE) {
    04798                     break;
    04799                 }
    04800                 KeDelayExecutionThread (KernelMode, FALSE, &MmShortTime);
    04801                 Count += 1;
    04802                 if (Count == 5) {
    04803
    04804                     //
    04805                     // Could not get the lock, don't trim this process.
    04806                     //
    04807
    04808                     return STATUS_SUCCESS;
    04809                 }
    04810             } while (TRUE);
    04811         }
    04812         if (Process->AddressSpaceDeleted != 0) {
    04813             Status = STATUS_PROCESS_IS_TERMINATING;
    04814             goto Deleted;
    04815         }
    04816     }
    04817     else {
    04818         if (WaitOk == TRUE) {
    04819             LOCK_SESSION_SPACE_WS (OldIrql);
    04820         }
    04821         else {
    04822             ASSERT (MiHydra == TRUE);
    04823             SessionSpace = CONTAINING_RECORD(WsInfo,
    04824                                              MM_SESSION_SPACE,
    04825                                              Vm);
    04826
    04827             KeRaiseIrql (APC_LEVEL, &OldIrql);
    04828
    04829             if (!ExTryToAcquireResourceExclusiveLite (&SessionSpace->WsLock)) {
    04830
    04831                 //
    04832                 // This session space's working set lock was not
    04833                 // granted, don't trim it.
    04834                 //
    04835
    04836                 KeLowerIrql (OldIrql);
    04837                 return STATUS_SUCCESS;
    04838             }
    04839
    04840             MM_SET_SESSION_RESOURCE_OWNER();
    04841         }
    04842     }
    04843
    04844     WorkingSetList = WsInfo->VmWorkingSetList;
    04845     Wsle = WorkingSetList->Wsle;
    04846
    04847     //
    04848     // Attempt to remove the pages starting at the bottom.
    04849     //
    04850
    04851     LastFreed = WorkingSetList->LastEntry;
    04852     for (Entry = WorkingSetList->FirstDynamic; Entry <= LastFreed; Entry += 1) {
    04853
    04854         if (Wsle[Entry].u1.e1.Valid != 0) {
    04855             PERFINFO_PAGE_INFO_DECL();
    04856
    04857             PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
    04858
    04859             PERFINFO_GET_PAGE_INFO(PointerPte);
    04860
    04861             if (MiTrimRemovalPagesOnly == TRUE) {
    04862                 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
    04863                 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    04864                 if (Pfn1->u3.e1.RemovalRequested == 0) {
    04865                     Pfn1 = MI_PFN_ELEMENT (Pfn1->PteFrame);
    04866                     if (Pfn1->u3.e1.RemovalRequested == 0) {
    04867 #if defined (_WIN64)
    04868                         Pfn1 = MI_PFN_ELEMENT (Pfn1->PteFrame);
    04869                         if (Pfn1->u3.e1.RemovalRequested == 0) {
    04870                             continue;
    04871                         }
    04872 #else
    04873                         continue;
    04874 #endif
    04875                     }
    04876                 }
    04877             }
    04878
    04879             if (MiFreeWsle (Entry, WsInfo, PointerPte)) {
    04880                 PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_EMPTYQ, WsInfo);
    04881             }
    04882         }
    04883     }
    04884
    04885     if (WsInfo != &MmSystemCacheWs && WsInfo->u.Flags.SessionSpace == 0) {
    04886         MiRemoveWorkingSetPages (WorkingSetList,WsInfo);
    04887     }
    04888     WorkingSetList->Quota = WsInfo->WorkingSetSize;
    04889     WorkingSetList->NextSlot = WorkingSetList->FirstDynamic;
    04890
    04891     //
    04892     // Attempt to remove the pages from the front to the end.
    04893     //
    04894
    04895     //
    04896     // Reorder the free list.
    04897     //
    04898
    04899     Last = 0;
    04900     Entry = WorkingSetList->FirstDynamic;
    04901     LastFreed = WorkingSetList->LastInitializedWsle;
    04902     while (Entry <= LastFreed) {
    04903         if (Wsle[Entry].u1.e1.Valid == 0) {
    04904             if (Last == 0) {
    04905                 WorkingSetList->FirstFree = Entry;
    04906             } else {
    04907                 Wsle[Last].u1.Long = Entry << MM_FREE_WSLE_SHIFT;
    04908             }
    04909             Last = Entry;
    04910         }
    04911         Entry += 1;
    04912     }
    04913     if (Last != 0) {
    04914         Wsle[Last].u1.Long = WSLE_NULL_INDEX << MM_FREE_WSLE_SHIFT;  // End of list.
    04915     }
    04916     Status = STATUS_SUCCESS;
    04917 Deleted:
    04918
    04919     if (WsInfo == &MmSystemCacheWs) {
    04920         UNLOCK_SYSTEM_WS (OldIrql);
    04921     }
    04922     else if (WsInfo->u.Flags.SessionSpace == 0) {
    04923         UNLOCK_WS (Process);
    04924     }
    04925     else {
    04926         UNLOCK_SESSION_SPACE_WS (OldIrql);
    04927     }
    04928
    04929     return Status;
    04930 }

ULONG MiFreeWsle | ( | IN WSLE_NUMBER | WorkingSetIndex,
|  | IN PMMSUPPORT | WsInfo,
|  | IN PMMPTE | PointerPte
| ) |

Definition at line 1326 of file wslist.c.

References ASSERT, _MMWSLE::e1, FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::LastInitializedWsle, LOCK_PFN, MI_IS_SESSION_ADDRESS, MI_PFN_ELEMENT, MiDumpWsleInCacheBlock(), MiEliminateWorkingSetEntry(), MiRemoveWsle(), MM_FREE_WSLE_SHIFT, MM_SYSTEM_WS_LOCK_ASSERT, MmPagesAboveWsMinimum, MmSystemCacheWs, PDE_TOP, TRUE, _MMWSLE::u1, _MMPFN::u2, _MMPFN::u3, UNLOCK_PFN, _MMWSLENTRY::Valid, _MMWSLE::VirtualAddress, _MMWSL::Wsle, and WSLE_NULL_INDEX.

Referenced by MiEmptyWorkingSet(), MiInsertWsle(), MiReplaceWorkingSetEntryUsingFaultInfo(), MiTrimWorkingSet(), MmAdjustWorkingSetSize(), and NtUnlockVirtualMemory().

    01334                    :
    01335
    01336     This routine frees the specified WSLE and decrements the share
    01337     count for the corresponding page, putting the PTE into a transition
    01338     state if the share count goes to 0.
    01339
    01340 Arguments:
    01341
    01342     WorkingSetIndex - Supplies the index of the working set entry to free.
    01343
    01344     WsInfo - Supplies a pointer to the working set structure (process or
    01345              system cache).
    01346
    01347     PointerPte - Supplies a pointer to the PTE for the working set entry.
    01348
    01349 Return Value:
    01350
    01351     Returns TRUE if the WSLE was removed, FALSE if it was not removed.
    01352         Pages with valid PTEs are not removed (i.e. page table pages
    01353         that contain valid or transition PTEs).
    01354
    01355 Environment:
    01356
    01357     Kernel mode, APCs disabled, working set lock.  PFN lock NOT held.
    01358
    01359 --*/
    01360
    01361 {
    01362     PMMPFN Pfn1;
    01363     PMMWSL WorkingSetList;
    01364     PMMWSLE Wsle;
    01365     KIRQL OldIrql;
    01366
    01367     WorkingSetList = WsInfo->VmWorkingSetList;
    01368     Wsle = WorkingSetList->Wsle;
    01369
    01370 #if DBG
    01371     if (WsInfo == &MmSystemCacheWs) {
    01372         MM_SYSTEM_WS_LOCK_ASSERT();
    01373     }
    01374 #endif //DBG
    01375
    01376     ASSERT (Wsle[WorkingSetIndex].u1.e1.Valid == 1);
    01377
    01378     //
    01379     // Check to see if the located entry is eligible for removal.
    01380     //
    01381
    01382     ASSERT (PointerPte->u.Hard.Valid == 1);
    01383
    01384     ASSERT (WorkingSetIndex >= WorkingSetList->FirstDynamic);
    01385
    01386     //
    01387     // Check to see if this is a page table with valid PTEs.
    01388     //
    01389     // Note, don't clear the access bit for page table pages
    01390     // with valid PTEs as this could cause an access trap fault which
    01391     // would not be handled (it is only handled for PTEs not PDEs).
    01392     //
    01393
    01394     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01395
    01396     LOCK_PFN (OldIrql);
    01397
    01398     //
    01399     // If the PTE is a page table page with non-zero share count or
    01400     // within the system cache with its reference count greater
    01401     // than 0, don't remove it.
    01402     //
    01403
    01404     if (WsInfo == &MmSystemCacheWs) {
    01405         if (Pfn1->u3.e2.ReferenceCount > 1) {
    01406             UNLOCK_PFN (OldIrql);
    01407             return FALSE;
    01408         }
    01409     } else {
    01410         if ((Pfn1->u2.ShareCount > 1) &&
    01411             (Pfn1->u3.e1.PrototypePte == 0)) {
    01412
    01413 #if DBG
    01414             if (WsInfo->u.Flags.SessionSpace == 1) {
    01415                 ASSERT (MI_IS_SESSION_ADDRESS (Wsle[WorkingSetIndex].u1.VirtualAddress));
    01416             }
    01417             else {
    01418                 ASSERT ((Wsle[WorkingSetIndex].u1.VirtualAddress >= (PVOID)PTE_BASE) &&
    01419                  (Wsle[WorkingSetIndex].u1.VirtualAddress<= (PVOID)PDE_TOP));
    01420             }
    01421 #endif
    01422
    01423             //
    01424             // Don't remove page table pages from the working set until
    01425             // all transition pages have exited.
    01426             //
    01427
    01428             UNLOCK_PFN (OldIrql);
    01429             return FALSE;
    01430         }
    01431     }
    01432
    01433     //
    01434     // Found a candidate, remove the page from the working set.
    01435     //
    01436
    01437     MiEliminateWorkingSetEntry (WorkingSetIndex,
    01438                                 PointerPte,
    01439                                 Pfn1,
    01440                                 Wsle);
    01441
    01442     UNLOCK_PFN (OldIrql);
    01443
    01444     //
    01445     // Remove the working set entry from the working set.
    01446     //
    01447
    01448     MiRemoveWsle (WorkingSetIndex, WorkingSetList);
    01449
    01450     ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
    01451
    01452     ASSERT (WorkingSetIndex >= WorkingSetList->FirstDynamic);
    01453
    01454     //
    01455     // Put the entry on the free list and decrement the current
    01456     // size.
    01457     //
    01458
    01459     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    01460             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    01461     Wsle[WorkingSetIndex].u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT;
    01462     WorkingSetList->FirstFree = WorkingSetIndex;
    01463     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    01464             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    01465
    01466     if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    01467         MmPagesAboveWsMinimum -= 1;
    01468     }
    01469     WsInfo->WorkingSetSize -= 1;
    01470
    01471 #if 0
    01472     if ((WsInfo == &MmSystemCacheWs) &&
    01473        (Pfn1->u3.e1.Modified == 1))  {
    01474         MiDumpWsleInCacheBlock (PointerPte);
    01475     }
    01476 #endif //0
    01477     return TRUE;
    01478 }

VOID MiGrowWsleHash | ( | IN PMMSUPPORT | WsInfo | ) |

Definition at line 3300 of file wslist.c.

References ASSERT, ASSERT32, ASSERT64, Count, FALSE, _MMWSL::HashTable, _MMWSL::HashTableSize, _MMWSL::HashTableStart, _MMWSL::HighestPermittedHashAddress, _MMWSL::LastInitializedWsle, LOCK_PFN, _MMWSLE::Long, MI_WSLE_HASH, MiAddWsleHash(), MiCheckWsleHash(), MiDeletePte(), MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteOnPdeBoundary, MmSystemCacheWs, MMWSLE_HASH, _MMWSL::NonDirectCount, NULL, _EPROCESS::NumberOfPrivatePages, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, PsGetCurrentProcess, Size, TRUE, _MMSUPPORT::u, _MMPTE::u, _MMWSLE::u1, UNLOCK_PFN, _MMWSLE::VirtualAddress, and _MMWSL::Wsle.

Referenced by MiInitializeSystemCache(), MiInitializeWorkingSetList(), MiMakeSpecialPoolPagable(), MiSessionInitializeWorkingSetList(), MmAccessFault(), and MmAdjustWorkingSetSize().

    03306                    :
    03307
    03308     This function grows (or adds) a hash table to the working set list
    03309     to allow direct indexing for WSLEs than cannot be located via the
    03310     PFN database WSINDEX field.
    03311
    03312     The hash table is located AFTER the WSLE array and the pages are
    03313     locked into the working set just like standard WSLEs.
    03314
    03315     Note that the hash table is expanded by setting the hash table
    03316     field in the working set to NULL, but leaving the size as non-zero.
    03317     This indicates that the hash should be expanded and the initial
    03318     portion of the table zeroed.
    03319
    03320 Arguments:
    03321
    03322     WsInfo - Supplies a pointer to the working set info block for the
    03323              process (or system cache).
    03324
    03325 Return Value:
    03326
    03327     None.
    03328
    03329 Environment:
    03330
    03331     Kernel mode, APCs disabled, working set lock held.
    03332
    03333 --*/
    03334 {
    03335     LONG Size;
    03336     PMMWSLE Wsle;
    03337     PMMPTE StartPte;
    03338     PMMPTE EndPte;
    03339     PMMPTE PointerPte;
    03340     PMMPTE PointerPde;
    03341     PMMPTE PointerPpe;
    03342     PMMPTE AllocatedPde;
    03343     PMMPTE AllocatedPpe;
    03344     ULONG First;
    03345     ULONG Hash;
    03346     ULONG NewSize;
    03347     PMMWSLE_HASH Table;
    03348     PMMWSLE_HASH OriginalTable;
    03349     ULONG j;
    03350     PMMWSL WorkingSetList;
    03351     KIRQL OldIrql;
    03352     ULONG Count;
    03353     LOGICAL LoopStart;
    03354     PVOID EntryHashTableEnd;
    03355     PVOID TempVa;
    03356     PEPROCESS CurrentProcess;
    03357
    03358     WorkingSetList = WsInfo->VmWorkingSetList;
    03359     Wsle = WorkingSetList->Wsle;
    03360
    03361     Table = WorkingSetList->HashTable;
    03362     OriginalTable = WorkingSetList->HashTable;
    03363
    03364     First = WorkingSetList->HashTableSize;
    03365
    03366     if (Table == NULL) {
    03367
    03368         NewSize = PtrToUlong(PAGE_ALIGN (((1 + WorkingSetList->NonDirectCount) *
    03369                             2 * sizeof(MMWSLE_HASH)) + PAGE_SIZE - 1));
    03370
    03371         //
    03372         // Note that the Table may be NULL and the HashTableSize/PTEs nonzero
    03373         // in the case where the hash has been contracted.
    03374         //
    03375
    03376         j = First * sizeof(MMWSLE_HASH);
    03377
    03378         //
    03379         // Don't try for additional hash pages if we already have
    03380         // the right amount (or too many).
    03381         //
    03382
    03383         if ((j + PAGE_SIZE > NewSize) && (j != 0)) {
    03384             return;
    03385         }
    03386
    03387         Table = (PMMWSLE_HASH)(WorkingSetList->HashTableStart);
    03388         EntryHashTableEnd = &Table[WorkingSetList->HashTableSize];
    03389
    03390         WorkingSetList->HashTableSize = 0;
    03391
    03392     } else {
    03393
    03394         //
    03395         // Attempt to add 4 pages, make sure the working set list has
    03396         // 4 free entries.
    03397         //
    03398
    03399         if ((WorkingSetList->LastInitializedWsle + 5) > WsInfo->WorkingSetSize) {
    03400             NewSize = PAGE_SIZE * 4;
    03401         } else {
    03402             NewSize = PAGE_SIZE;
    03403         }
    03404         EntryHashTableEnd = &Table[WorkingSetList->HashTableSize];
    03405     }
    03406
    03407     if ((PCHAR)EntryHashTableEnd + NewSize > (PCHAR)WorkingSetList->HighestPermittedHashAddress) {
    03408         NewSize =
    03409             (ULONG)((PCHAR)(WorkingSetList->HighestPermittedHashAddress) -
    03410                 ((PCHAR)EntryHashTableEnd));
    03411         if (NewSize == 0) {
    03412             if (OriginalTable == NULL) {
    03413                 WorkingSetList->HashTableSize = First;
    03414             }
    03415             return;
    03416         }
    03417     }
    03418
    03419     ASSERT64 ((MiGetPpeAddress(EntryHashTableEnd)->u.Hard.Valid == 0) ||
    03420               (MiGetPdeAddress(EntryHashTableEnd)->u.Hard.Valid == 0) ||
    03421               (MiGetPteAddress(EntryHashTableEnd)->u.Hard.Valid == 0));
    03422
    03423     ASSERT32 (MiGetPteAddress(EntryHashTableEnd)->u.Hard.Valid == 0);
    03424
    03425     Size = NewSize;
    03426     PointerPte = MiGetPteAddress (EntryHashTableEnd);
    03427     StartPte = PointerPte;
    03428     EndPte = PointerPte + (NewSize >> PAGE_SHIFT);
    03429
    03430 #if defined (_WIN64)
    03431     LoopStart = TRUE;
    03432     AllocatedPde = NULL;
    03433     AllocatedPpe = NULL;
    03434 #endif
    03435
    03436     do {
    03437
    03438 #if defined (_WIN64)
    03439         if (LoopStart == TRUE || MiIsPteOnPdeBoundary(PointerPte)) {
    03440
    03441             PointerPpe = MiGetPdeAddress(PointerPte);
    03442             PointerPde = MiGetPteAddress(PointerPte);
    03443
    03444             if (PointerPpe->u.Hard.Valid == 0) {
    03445                 if (MiAddWsleHash (WsInfo, PointerPpe) == FALSE) {
    03446                     break;
    03447                 }
    03448                 AllocatedPpe = PointerPpe;
    03449             }
    03450
    03451             if (PointerPde->u.Hard.Valid == 0) {
    03452                 if (MiAddWsleHash (WsInfo, PointerPde) == FALSE) {
    03453                     break;
    03454                 }
    03455                 AllocatedPde = PointerPde;
    03456             }
    03457
    03458             LoopStart = FALSE;
    03459         }
    03460         else {
    03461             AllocatedPde = NULL;
    03462             AllocatedPpe = NULL;
    03463         }
    03464 #endif
    03465
    03466         if (PointerPte->u.Hard.Valid == 0) {
    03467             if (MiAddWsleHash (WsInfo, PointerPte) == FALSE) {
    03468                 break;
    03469             }
    03470         }
    03471
    03472         PointerPte += 1;
    03473         Size -= PAGE_SIZE;
    03474     } while (Size > 0);
    03475
    03476     //
    03477     // If MiAddWsleHash was unable to allocate memory above, then roll back
    03478     // any extra PPEs & PDEs that may have been created.  Note NewSize must
    03479     // be recalculated to handle the fact that memory may have run out.
    03480     //
    03481
    03482 #if !defined (_WIN64)
    03483     if (PointerPte == StartPte) {
    03484         if (OriginalTable == NULL) {
    03485             WorkingSetList->HashTableSize = First;
    03486         }
    03487         return;
    03488     }
    03489 #else
    03490     if (PointerPte != EndPte) {
    03491
    03492         //
    03493         // Clean up the last allocated PPE/PDE as they are not needed.
    03494         // Note that the system cache and the session space working sets
    03495         // have no current process (which MiDeletePte requires) which is
    03496         // needed for WSLE and PrivatePages adjustments.
    03497         //
    03498
    03499         if (WsInfo != &MmSystemCacheWs && WsInfo->u.Flags.SessionSpace == 0) {
    03500             CurrentProcess = PsGetCurrentProcess();
    03501
    03502             if (AllocatedPde != NULL) {
    03503                 ASSERT (AllocatedPde->u.Hard.Valid == 1);
    03504                 TempVa = MiGetVirtualAddressMappedByPte(AllocatedPde);
    03505                 LOCK_PFN (OldIrql);
    03506                 MiDeletePte (AllocatedPde,
    03507                              TempVa,
    03508                              FALSE,
    03509                              CurrentProcess,
    03510                              NULL,
    03511                              NULL);
    03512                 //
    03513                 // Add back in the private page MiDeletePte subtracted.
    03514                 //
    03515
    03516                 CurrentProcess->NumberOfPrivatePages += 1;
    03517                 UNLOCK_PFN (OldIrql);
    03518             }
    03519
    03520             if (AllocatedPpe != NULL) {
    03521                 ASSERT (AllocatedPpe->u.Hard.Valid == 1);
    03522                 TempVa = MiGetVirtualAddressMappedByPte(AllocatedPpe);
    03523                 LOCK_PFN (OldIrql);
    03524                 MiDeletePte (AllocatedPpe,
    03525                              TempVa,
    03526                              FALSE,
    03527                              CurrentProcess,
    03528                              NULL,
    03529                              NULL);
    03530                 //
    03531                 // Add back in the private page MiDeletePte subtracted.
    03532                 //
    03533
    03534                 CurrentProcess->NumberOfPrivatePages += 1;
    03535                 UNLOCK_PFN (OldIrql);
    03536             }
    03537         }
    03538
    03539         if (PointerPte == StartPte) {
    03540             if (OriginalTable == NULL) {
    03541                 WorkingSetList->HashTableSize = First;
    03542             }
    03543         }
    03544
    03545         return;
    03546     }
    03547 #endif
    03548
    03549     NewSize = (ULONG)((PointerPte - StartPte) << PAGE_SHIFT);
    03550
    03551     ASSERT ((MiGetVirtualAddressMappedByPte(PointerPte) == WorkingSetList->HighestPermittedHashAddress) ||
    03552             (PointerPte->u.Hard.Valid == 0));
    03553
    03554     WorkingSetList->HashTableSize = First + NewSize / sizeof (MMWSLE_HASH);
    03555     WorkingSetList->HashTable = Table;
    03556
    03557     ASSERT ((&Table[WorkingSetList->HashTableSize] == WorkingSetList->HighestPermittedHashAddress) ||
    03558         (MiGetPteAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0));
    03559
    03560     if (First != 0) {
    03561         RtlZeroMemory (Table, First * sizeof(MMWSLE_HASH));
    03562     }
    03563
    03564     //
    03565     // Fill hash table
    03566     //
    03567
    03568     j = 0;
    03569     Count = WorkingSetList->NonDirectCount;
    03570
    03571     Size = WorkingSetList->HashTableSize;
    03572
    03573     do {
    03574         if ((Wsle[j].u1.e1.Valid == 1) &&
    03575             (Wsle[j].u1.e1.Direct == 0)) {
    03576
    03577             //
    03578             // Hash this.
    03579             //
    03580
    03581             Count -= 1;
    03582
    03583             Hash = MI_WSLE_HASH(Wsle[j].u1.Long, WorkingSetList);
    03584
    03585             while (Table[Hash].Key != 0) {
    03586                 Hash += 1;
    03587                 if (Hash >= (ULONG)Size) {
    03588                     Hash = 0;
    03589                 }
    03590             }
    03591
    03592             Table[Hash].Key = Wsle[j].u1.Long & ~(PAGE_SIZE - 1);
    03593             Table[Hash].Index = j;
    03594 #if DBG
    03595             PointerPte = MiGetPteAddress(Wsle[j].u1.VirtualAddress);
    03596             ASSERT (PointerPte->u.Hard.Valid);
    03597 #endif //DBG
    03598
    03599         }
    03600         ASSERT (j <= WorkingSetList->LastEntry);
    03601         j += 1;
    03602     } while (Count);
    03603
    03604 #if DBG
    03605     MiCheckWsleHash (WorkingSetList);
    03606 #endif //DBG
    03607     return;
    03608 }

VOID MiInitializeSessionWsSupport | ( | VOID |  | ) |

Definition at line 1847 of file wslist.c.

References MiSessionWsList.

Referenced by MmInitSystem().

    01853                    :
    01854
    01855     This routine initializes the session space working set support.
    01856
    01857 Arguments:
    01858
    01859     None.
    01860
    01861 Return Value:
    01862
    01863     None.
    01864
    01865 Environment:
    01866
    01867     Kernel mode, APC_LEVEL or below, no mutexes held.
    01868
    01869 --*/
    01870
    01871 {
    01872     //
    01873     // This is the list of all session spaces ordered in a working set list.
    01874     //
    01875
    01876     InitializeListHead (&MiSessionWsList);
    01877 }

VOID MiInitializeWorkingSetList | ( | IN PEPROCESS | CurrentProcess | ) |

Definition at line 1481 of file wslist.c.

References ASSERT, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, _MMWSL::HashTableSize, _MMWSL::HashTableStart, _MMWSL::HighestPermittedHashAddress, HYPER_SPACE, HYPER_SPACE_END, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_PFN, MI_MAKE_VALID_PTE, MI_PAGE_COLOR_PTE_PROCESS, MI_PFN_ELEMENT, MI_SET_PTE_DIRTY, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiEnsureAvailablePageOrWait(), MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiGrowWsleHash(), MiInitializePfn(), MiRemoveZeroPage(), MM_DEMAND_ZERO_WRITE_PTE, MM_FREE_WSLE_SHIFT, MM_MAXIMUM_WORKING_SET, MM_READWRITE, MM_SESSION_SPACE_DEFAULT, MmWorkingSetList, MmWsle, _MMWSL::NextSlot, NULL, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, _MMWSL::Quota, _MMPTE::u, _MMPFN::u1, _MMWSLE::u1, UNLOCK_PFN, _MMWSL::WaitingForImageMapping, WORKING_SET_LIST, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MmInitializeProcessAddressSpace().

    01487                    :
    01488
    01489     This routine initializes a process's working set to the empty
    01490     state.
    01491
    01492 Arguments:
    01493
    01494     CurrentProcess - Supplies a pointer to the process to initialize.
    01495
    01496 Return Value:
    01497
    01498     None.
    01499
    01500 Environment:
    01501
    01502     Kernel mode, APCs disabled.
    01503
    01504 --*/
    01505
    01506 {
    01507     ULONG i;
    01508     PMMWSLE WslEntry;
    01509     ULONG CurrentEntry;
    01510     PMMPTE PointerPte;
    01511     PMMPFN Pfn1;
    01512     WSLE_NUMBER NumberOfEntriesMapped;
    01513     ULONG_PTR CurrentVa;
    01514     PFN_NUMBER WorkingSetPage;
    01515     MMPTE TempPte;
    01516     KIRQL OldIrql;
    01517
    01518     WslEntry = MmWsle;
    01519
    01520     //
    01521     // Initialize the temporary double mapping portion of hyperspace, if
    01522     // it has not already been done.
    01523     //
    01524     // Initialize the working set list control cells.
    01525     //
    01526
    01527     MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
    01528     MmWorkingSetList->Quota = MmWorkingSetList->LastEntry;
    01529     MmWorkingSetList->WaitingForImageMapping = (PKEVENT)NULL;
    01530     MmWorkingSetList->HashTable = NULL;
    01531     MmWorkingSetList->HashTableSize = 0;
    01532     MmWorkingSetList->Wsle = MmWsle;
    01533     MmWorkingSetList->HashTableStart =
    01534        (PVOID)((PCHAR)PAGE_ALIGN (&MmWsle[MM_MAXIMUM_WORKING_SET]) + PAGE_SIZE);
    01535
    01536     MmWorkingSetList->HighestPermittedHashAddress = (PVOID)(HYPER_SPACE_END + 1);
    01537
    01538     //
    01539     // Fill in the reserved slots.  Start with the page directory page.
    01540     //
    01541
    01542 #if !defined (_X86PAE_)
    01543
    01544     WslEntry->u1.Long = PDE_BASE;
    01545     WslEntry->u1.e1.Valid = 1;
    01546     WslEntry->u1.e1.LockedInWs = 1;
    01547     WslEntry->u1.e1.Direct = 1;
    01548
    01549     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01550     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01551
    01552     CONSISTENCY_LOCK_PFN (OldIrql);
    01553
    01554 #if !defined (_WIN64)
    01555     Pfn1->u1.Event = (PVOID)CurrentProcess;
    01556 #endif
    01557
    01558     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01559
    01560 #else
    01561
    01562     //
    01563     // Fill in all the page directory entries.
    01564     //
    01565
    01566     for (i = 0; i < PD_PER_SYSTEM; i += 1) {
    01567
    01568         WslEntry->u1.VirtualAddress = (PVOID)(PDE_BASE + i * PAGE_SIZE);
    01569         WslEntry->u1.e1.Valid = 1;
    01570         WslEntry->u1.e1.LockedInWs = 1;
    01571         WslEntry->u1.e1.Direct = 1;
    01572
    01573         PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01574         Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01575
    01576         ASSERT (Pfn1->u1.WsIndex == 0);
    01577
    01578         CONSISTENCY_LOCK_PFN (OldIrql);
    01579
    01580         Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01581
    01582         CONSISTENCY_UNLOCK_PFN (OldIrql);
    01583
    01584         WslEntry += 1;
    01585     }
    01586     WslEntry -= 1;
    01587
    01588 #endif
    01589
    01590
    01591 #if defined (_WIN64)
    01592
    01593     //
    01594     // Fill in the entry for the page directory parent page.
    01595     //
    01596
    01597     WslEntry += 1;
    01598
    01599     WslEntry->u1.Long = PDE_TBASE;
    01600     WslEntry->u1.e1.Valid = 1;
    01601     WslEntry->u1.e1.LockedInWs = 1;
    01602     WslEntry->u1.e1.Direct = 1;
    01603
    01604     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01605     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01606
    01607     ASSERT (Pfn1->u1.WsIndex == 0);
    01608
    01609     CONSISTENCY_LOCK_PFN (OldIrql);
    01610
    01611     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01612
    01613     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01614
    01615     //
    01616     // Fill in the entry for the hyper space page directory page.
    01617     //
    01618
    01619     WslEntry += 1;
    01620
    01621     WslEntry->u1.VirtualAddress = (PVOID)MiGetPdeAddress (HYPER_SPACE);
    01622     WslEntry->u1.e1.Valid = 1;
    01623     WslEntry->u1.e1.LockedInWs = 1;
    01624     WslEntry->u1.e1.Direct = 1;
    01625
    01626     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01627     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01628
    01629     ASSERT (Pfn1->u1.WsIndex == 0);
    01630
    01631     CONSISTENCY_LOCK_PFN (OldIrql);
    01632
    01633     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01634
    01635     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01636
    01637 #if defined (_IA64_)
    01638
    01639     //
    01640     // Fill in the entry for the session space page directory parent page.
    01641     //
    01642
    01643     WslEntry += 1;
    01644
    01645     WslEntry->u1.VirtualAddress = (PVOID)MiGetPpeAddress (MM_SESSION_SPACE_DEFAULT);
    01646     WslEntry->u1.e1.Valid = 1;
    01647     WslEntry->u1.e1.LockedInWs = 1;
    01648     WslEntry->u1.e1.Direct = 1;
    01649
    01650     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01651     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01652
    01653     ASSERT (Pfn1->u1.WsIndex == 0);
    01654
    01655     CONSISTENCY_LOCK_PFN (OldIrql);
    01656
    01657     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01658
    01659     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01660
    01661 #endif
    01662
    01663 #endif
    01664
    01665     //
    01666     // Fill in the entry for the page table page which maps hyper space.
    01667     //
    01668
    01669     WslEntry += 1;
    01670
    01671     WslEntry->u1.VirtualAddress = (PVOID)MiGetPteAddress (HYPER_SPACE);
    01672     WslEntry->u1.e1.Valid = 1;
    01673     WslEntry->u1.e1.LockedInWs = 1;
    01674     WslEntry->u1.e1.Direct = 1;
    01675
    01676     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01677     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01678
    01679     ASSERT (Pfn1->u1.WsIndex == 0);
    01680
    01681     CONSISTENCY_LOCK_PFN (OldIrql);
    01682
    01683     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01684
    01685     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01686
    01687 #if defined (_X86PAE_)
    01688
    01689     //
    01690     // Fill in the entry for the second page table page which maps hyper space.
    01691     //
    01692
    01693     WslEntry += 1;
    01694
    01695     WslEntry->u1.VirtualAddress = (PVOID)MiGetPteAddress (HYPER_SPACE2);
    01696     WslEntry->u1.e1.Valid = 1;
    01697     WslEntry->u1.e1.LockedInWs = 1;
    01698     WslEntry->u1.e1.Direct = 1;
    01699
    01700     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01701     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01702
    01703     ASSERT (Pfn1->u1.WsIndex == 0);
    01704
    01705     CONSISTENCY_LOCK_PFN (OldIrql);
    01706
    01707     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01708
    01709     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01710
    01711 #endif
    01712
    01713     //
    01714     // Fill in the entry for the page which contains the working set list.
    01715     //
    01716
    01717     WslEntry += 1;
    01718
    01719     WslEntry->u1.VirtualAddress = (PVOID)MmWorkingSetList;
    01720     WslEntry->u1.e1.Valid = 1;
    01721     WslEntry->u1.e1.LockedInWs = 1;
    01722     WslEntry->u1.e1.Direct = 1;
    01723
    01724     PointerPte = MiGetPteAddress (WslEntry->u1.VirtualAddress);
    01725     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01726
    01727     ASSERT (Pfn1->u1.WsIndex == 0);
    01728
    01729     CONSISTENCY_LOCK_PFN (OldIrql);
    01730
    01731     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmWsle);
    01732
    01733     CONSISTENCY_UNLOCK_PFN (OldIrql);
    01734
    01735     CurrentEntry = (WSLE_NUMBER)((WslEntry - MmWsle) + 1);
    01736
    01737     //
    01738     // Check to see if more pages are required in the working set list
    01739     // to map the current maximum working set size.
    01740     //
    01741
    01742     NumberOfEntriesMapped = (WSLE_NUMBER)(((PMMWSLE)((PCHAR)WORKING_SET_LIST + PAGE_SIZE)) -
    01743                                 MmWsle);
    01744
    01745     if (CurrentProcess->Vm.MaximumWorkingSetSize >= NumberOfEntriesMapped) {
    01746
    01747         PointerPte = MiGetPteAddress (&MmWsle[0]);
    01748
    01749         CurrentVa = (ULONG_PTR)MmWorkingSetList + PAGE_SIZE;
    01750
    01751         //
    01752         // The working set requires more than a single page.
    01753         //
    01754
    01755         LOCK_PFN (OldIrql);
    01756
    01757         do {
    01758
    01759             MiEnsureAvailablePageOrWait (NULL, NULL);
    01760
    01761             PointerPte += 1;
    01762             WorkingSetPage = MiRemoveZeroPage (
    01763                                     MI_PAGE_COLOR_PTE_PROCESS (PointerPte,
    01764                                               &CurrentProcess->NextPageColor));
    01765             PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE;
    01766
    01767             MiInitializePfn (WorkingSetPage, PointerPte, 1);
    01768
    01769             MI_MAKE_VALID_PTE (TempPte,
    01770                                WorkingSetPage,
    01771                                MM_READWRITE,
    01772                                PointerPte );
    01773
    01774             MI_SET_PTE_DIRTY (TempPte);
    01775
    01776             MI_SET_PTE_IN_WORKING_SET (&TempPte, CurrentEntry);
    01777
    01778             MI_WRITE_VALID_PTE (PointerPte, TempPte);
    01779
    01780             WslEntry += 1;
    01781
    01782             WslEntry->u1.Long = CurrentVa;
    01783             WslEntry->u1.e1.Valid = 1;
    01784             WslEntry->u1.e1.LockedInWs = 1;
    01785             WslEntry->u1.e1.Direct = 1;
    01786
    01787             Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01788
    01789             ASSERT (Pfn1->u1.WsIndex == 0);
    01790             Pfn1->u1.WsIndex = CurrentEntry;
    01791
    01792             // MiInsertWsle(CurrentEntry, MmWorkingSetList);
    01793
    01794             CurrentEntry += 1;
    01795             CurrentVa += PAGE_SIZE;
    01796
    01797             NumberOfEntriesMapped += PAGE_SIZE / sizeof(MMWSLE);
    01798
    01799         } while (CurrentProcess->Vm.MaximumWorkingSetSize >= NumberOfEntriesMapped);
    01800
    01801         UNLOCK_PFN (OldIrql);
    01802     }
    01803
    01804     CurrentProcess->Vm.WorkingSetSize = CurrentEntry;
    01805     MmWorkingSetList->FirstFree = CurrentEntry;
    01806     MmWorkingSetList->FirstDynamic = CurrentEntry;
    01807     MmWorkingSetList->NextSlot = CurrentEntry;
    01808
    01809     //
    01810     // Initialize the following slots as free.
    01811     //
    01812
    01813     i = CurrentEntry + 1;
    01814     do {
    01815
    01816         //
    01817         // Build the free list, note that the first working
    01818         // set entries (CurrentEntry) are not on the free list.
    01819         // These entries are reserved for the pages which
    01820         // map the working set and the page which contains the PDE.
    01821         //
    01822
    01823         WslEntry += 1;
    01824         WslEntry->u1.Long = i << MM_FREE_WSLE_SHIFT;
    01825         i += 1;
    01826     } while (i <= NumberOfEntriesMapped);
    01827
    01828     WslEntry->u1.Long = WSLE_NULL_INDEX << MM_FREE_WSLE_SHIFT;  // End of list.
    01829
    01830     MmWorkingSetList->LastInitializedWsle =
    01831                                 NumberOfEntriesMapped - 1;
    01832
    01833     if (CurrentProcess->Vm.MaximumWorkingSetSize > ((1536*1024) >> PAGE_SHIFT)) {
    01834
    01835         //
    01836         // The working set list consists of more than a single page.
    01837         //
    01838
    01839         MiGrowWsleHash (&CurrentProcess->Vm);
    01840     }
    01841
    01842     return;
    01843 }

WSLE_NUMBER MiLocateAndReserveWsle | ( | IN PMMSUPPORT | WsInfo | ) |

Definition at line 117 of file wslist.c.

References ASSERT, _MMWSLE::e1, FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, MiAddWorkingSetPage(), MiDoReplacement(), MM_FREE_WSLE_SHIFT, MmInfoCounters, MmPagesAboveWsMinimum, MmSystemCacheWs, MmTransitionSharedPages, MmTransitionSharedPagesPeak, _MMINFO_COUNTERS::PageFaultCount, _MMWSL::Quota, TRUE, _MMWSLE::u1, _MMWSLENTRY::Valid, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MiAddValidPageToWorkingSet(), MiAddWsleHash(), MiLockCode(), MmAccessFault(), MmCheckCachedPageState(), and MmCopyToCachedPage().

    00123                    :
    00124
    00125     This function examines the Working Set List for the current
    00126     process and locates an entry to contain a new page.  If the
    00127     working set is not currently at its quota, the new page is
    00128     added without removing a page, if the working set is at its
    00129     quota a page is removed from the working set and the new
    00130     page added in its place.
    00131
    00132 Arguments:
    00133
    00134     None.
    00135
    00136 Return Value:
    00137
    00138     Returns the working set index which is now reserved for the
    00139     next page to be added.
    00140
    00141 Environment:
    00142
    00143     Kernel mode, APCs disabled, working set lock.  PFN lock NOT held.
    00144
    00145 --*/
    00146
    00147 {
    00148     WSLE_NUMBER WorkingSetIndex;
    00149     PMMWSL WorkingSetList;
    00150     PMMWSLE Wsle;
    00151     ULONG QuotaIncrement;
    00152     BOOLEAN MustReplace;
    00153
    00154     MustReplace = FALSE;
    00155     WorkingSetList = WsInfo->VmWorkingSetList;
    00156     Wsle = WorkingSetList->Wsle;
    00157
    00158     //
    00159     // Update page fault counts.
    00160     //
    00161
    00162     WsInfo->PageFaultCount += 1;
    00163     MmInfoCounters.PageFaultCount += 1;
    00164
    00165     //
    00166     // Determine if a page should be removed from the working set to make
    00167     // room for the new page.  If so, remove it.  In addition, determine
    00168     // the size of the QuotaIncrement if the size needs to be boosted.
    00169     //
    00170
    00171 retry_replacement:
    00172
    00173     QuotaIncrement = MiDoReplacement(WsInfo, MustReplace);
    00174
    00175     ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->Quota);
    00176     WsInfo->WorkingSetSize += 1;
    00177
    00178     if (WsInfo->WorkingSetSize > WorkingSetList->Quota) {
    00179
    00180         //
    00181         // Increment the quota and check boundary conditions.
    00182         //
    00183
    00184         WorkingSetList->Quota += QuotaIncrement;
    00185
    00186         WsInfo->LastTrimFaultCount = WsInfo->PageFaultCount;
    00187
    00188         if (WorkingSetList->Quota > WorkingSetList->LastInitializedWsle) {
    00189
    00190             //
    00191             // Add more pages to the working set list structure.
    00192             //
    00193
    00194             if (MiAddWorkingSetPage (WsInfo) == TRUE) {
    00195                 ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->Quota);
    00196             }
    00197             else {
    00198
    00199                 //
    00200                 // No page was added to the working set list structure.
    00201                 // We must replace a page within this working set.
    00202                 //
    00203
    00204                 WsInfo->WorkingSetSize -= 1;
    00205                 MustReplace = TRUE;
    00206                 goto retry_replacement;
    00207             }
    00208         }
    00209     }
    00210
    00211     //
    00212     // Get the working set entry from the free list.
    00213     //
    00214
    00215     ASSERT (WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle);
    00216
    00217     ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
    00218
    00219     WorkingSetIndex = WorkingSetList->FirstFree;
    00220     WorkingSetList->FirstFree = (WSLE_NUMBER)(Wsle[WorkingSetIndex].u1.Long >> MM_FREE_WSLE_SHIFT);
    00221
    00222     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    00223             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    00224
    00225     if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    00226         MmPagesAboveWsMinimum += 1;
    00227     }
    00228
    00229     if (WsInfo->WorkingSetSize > WsInfo->PeakWorkingSetSize) {
    00230         WsInfo->PeakWorkingSetSize = WsInfo->WorkingSetSize;
    00231     }
    00232
    00233     if (WsInfo == &MmSystemCacheWs) {
    00234         if (WsInfo->WorkingSetSize + MmTransitionSharedPages > MmTransitionSharedPagesPeak) {
    00235             MmTransitionSharedPagesPeak = WsInfo->WorkingSetSize + MmTransitionSharedPages;
    00236         }
    00237     }
    00238
    00239     if (WorkingSetIndex > WorkingSetList->LastEntry) {
    00240         WorkingSetList->LastEntry = WorkingSetIndex;
    00241     }
    00242
    00243     //
    00244     // The returned entry is guaranteed to be available at this point.
    00245     //
    00246
    00247     ASSERT (Wsle[WorkingSetIndex].u1.e1.Valid == 0);
    00248
    00249     return WorkingSetIndex;
    00250 }

VOID MiReleaseWsle | ( | IN WSLE_NUMBER | WorkingSetIndex,
|  | IN PMMSUPPORT | WsInfo
| ) |

Definition at line 1016 of file wslist.c.

References ASSERT, _MMWSL::FirstFree, _MMWSL::LastInitializedWsle, MM_FREE_WSLE_SHIFT, MM_SYSTEM_WS_LOCK_ASSERT, MmPagesAboveWsMinimum, MmSystemCacheWs, _MMWSLE::u1, _MMWSL::Wsle, and WSLE_NULL_INDEX.

Referenced by MiDecommitPages(), MiDeleteAddressesInWorkingSet(), MiDeletePte(), MiDeleteSystemPagableVm(), MiLockCode(), MiRemoveMappedPtes(), MiRemovePageFromWorkingSet(), and MmUnmapViewInSystemCache().

    01023                    :
    01024
    01025     This function releases a previously reserved working set entry to
    01026     be reused.  A release occurs when a page fault is retried due to
    01027     changes in PTEs and working sets during an I/O operation.
    01028
    01029 Arguments:
    01030
    01031     WorkingSetIndex - Supplies the index of the working set entry to
    01032                       release.
    01033
    01034 Return Value:
    01035
    01036     None.
    01037
    01038 Environment:
    01039
    01040     Kernel mode, APCs disabled, working set lock held and PFN lock held.
    01041
    01042 --*/
    01043
    01044 {
    01045     PMMWSL WorkingSetList;
    01046     PMMWSLE Wsle;
    01047
    01048     WorkingSetList = WsInfo->VmWorkingSetList;
    01049     Wsle = WorkingSetList->Wsle;
    01050 #if DBG
    01051     if (WsInfo == &MmSystemCacheWs) {
    01052         MM_SYSTEM_WS_LOCK_ASSERT();
    01053     }
    01054 #endif //DBG
    01055
    01056     ASSERT (WorkingSetIndex <= WorkingSetList->LastInitializedWsle);
    01057
    01058     //
    01059     // Put the entry on the free list and decrement the current
    01060     // size.
    01061     //
    01062
    01063     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    01064             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    01065     Wsle[WorkingSetIndex].u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT;
    01066     WorkingSetList->FirstFree = WorkingSetIndex;
    01067     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    01068             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    01069     if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
    01070         MmPagesAboveWsMinimum -= 1;
    01071     }
    01072     WsInfo->WorkingSetSize -= 1;
    01073     return;
    01074
    01075 }

ULONG MiRemovePageFromWorkingSet | ( | IN PMMPTE | PointerPte,
|  | IN PMMPFN | Pfn1,
|  | IN PMMSUPPORT | WsInfo
| ) |

Definition at line 899 of file wslist.c.

References ASSERT, FALSE, _MMWSL::FirstDynamic, LOCK_PFN, _MMWSLENTRY::LockedInMemory, _MMWSLENTRY::LockedInWs, MI_PFN_ELEMENT, MiEliminateWorkingSetEntry(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiLocateWsle(), MiReleaseWsle(), MiRemoveWsle(), MiSwapWslEntries(), PAGE_ALIGN, TRUE, _MMWSLE::u1, UNLOCK_PFN, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MiProtectSpecialPool(), MiProtectVirtualMemory(), and MiSetProtectionOnSection().

    00907                    :
    00908
    00909     This function removes the page mapped by the specified PTE from
    00910     the process's working set list.
    00911
    00912 Arguments:
    00913
    00914     PointerPte - Supplies a pointer to the PTE mapping the page to
    00915                  be removed from the working set list.
    00916
    00917     Pfn1 - Supplies a pointer to the PFN database element referred to
    00918            by the PointerPte.
    00919
    00920 Return Value:
    00921
    00922     Returns TRUE if the specified page was locked in the working set,
    00923     FALSE otherwise.
    00924
    00925 Environment:
    00926
    00927     Kernel mode, APCs disabled, working set mutex held.
    00928
    00929 --*/
    00930
    00931 {
    00932     WSLE_NUMBER WorkingSetIndex;
    00933     PVOID VirtualAddress;
    00934     WSLE_NUMBER Entry;
    00935     PVOID SwapVa;
    00936     MMWSLENTRY Locked;
    00937     PMMWSL WorkingSetList;
    00938     PMMWSLE Wsle;
    00939     KIRQL OldIrql;
    00940
    00941     WorkingSetList = WsInfo->VmWorkingSetList;
    00942     Wsle = WorkingSetList->Wsle;
    00943
    00944     VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte);
    00945     WorkingSetIndex = MiLocateWsle (VirtualAddress,
    00946                                     WorkingSetList,
    00947                                     Pfn1->u1.WsIndex);
    00948
    00949     ASSERT (WorkingSetIndex != WSLE_NULL_INDEX);
    00950     LOCK_PFN (OldIrql);
    00951     MiEliminateWorkingSetEntry (WorkingSetIndex,
    00952                                 PointerPte,
    00953                                 Pfn1,
    00954                                 Wsle);
    00955
    00956     UNLOCK_PFN (OldIrql);
    00957
    00958     //
    00959     // Check to see if this entry is locked in the working set
    00960     // or locked in memory.
    00961     //
    00962
    00963     Locked = Wsle[WorkingSetIndex].u1.e1;
    00964     MiRemoveWsle (WorkingSetIndex, WorkingSetList);
    00965
    00966     //
    00967     // Add this entry to the list of free working set entries
    00968     // and adjust the working set count.
    00969     //
    00970
    00971     MiReleaseWsle ((WSLE_NUMBER)WorkingSetIndex, WsInfo);
    00972
    00973     if ((Locked.LockedInWs == 1) || (Locked.LockedInMemory == 1)) {
    00974
    00975         //
    00976         // This entry is locked.
    00977         //
    00978
    00979         WorkingSetList->FirstDynamic -= 1;
    00980
    00981         if (WorkingSetIndex != WorkingSetList->FirstDynamic) {
    00982
    00983             SwapVa = Wsle[WorkingSetList->FirstDynamic].u1.VirtualAddress;
    00984             SwapVa = PAGE_ALIGN (SwapVa);
    00985
    00986             PointerPte = MiGetPteAddress (SwapVa);
    00987             Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    00988 #if 0
    00989             Entry = MiLocateWsleAndParent (SwapVa,
    00990                                            &Parent,
    00991                                            WorkingSetList,
    00992                                            Pfn1->u1.WsIndex);
    00993
    00994             //
    00995             // Swap the removed entry with the last locked entry
    00996             // which is located at first dynamic.
    00997             //
    00998
    00999             MiSwapWslEntries (Entry, Parent, WorkingSetIndex, WorkingSetList);
    01000 #endif //0
    01001
    01002             Entry = MiLocateWsle (SwapVa, WorkingSetList, Pfn1->u1.WsIndex);
    01003
    01004             MiSwapWslEntries (Entry, WorkingSetIndex, WsInfo);
    01005
    01006         }
    01007         return TRUE;
    01008     } else {
    01009         ASSERT (WorkingSetIndex >= WorkingSetList->FirstDynamic);
    01010     }
    01011     return FALSE;
    01012 }

VOID MiRemoveWorkingSetPages | ( | IN PMMWSL | WorkingSetList,
|  | IN PMMSUPPORT | WsInfo
| ) |

| Referenced by MiEmptyWorkingSet(), and MiTrimWorkingSet().

VOID MiReplaceWorkingSetEntryUsingFaultInfo | ( | IN PMMSUPPORT | WsInfo,
|  | IN BOOLEAN | MustReplace
| ) |

Definition at line 790 of file wslist.c.

References _MMWSL::FirstDynamic, _MMWSL::LastEntry, MI_GET_ACCESSED_IN_PTE, MI_SET_ACCESSED_IN_PTE, MiFreeWsle(), MiGetPteAddress, MM_WORKING_SET_LIST_SEARCH, _MMWSL::NextSlot, PERFINFO_GET_PAGE_INFO_REPLACEMENT, PERFINFO_LOG_WS_REPLACEMENT, PERFINFO_PAGE_INFO_REPLACEMENT_DECL, TRUE, _MMWSLE::u1, _MMWSLE::VirtualAddress, and _MMWSL::Wsle.

Referenced by MiDoReplacement().

    00797                    :
    00798
    00799     This function tries to find a reasonable working set entry to replace.
    00800
    00801 Arguments:
    00802
    00803     WsInfo - Supplies the working set info pointer.
    00804
    00805     MustReplace - Supplies TRUE if replacement must succeed.
    00806
    00807 Return Value:
    00808
    00809     None
    00810
    00811 Environment:
    00812
    00813     Kernel mode, APCs disabled, working set lock.  PFN lock NOT held.
    00814
    00815 --*/
    00816
    00817 {
    00818     ULONG WorkingSetIndex;
    00819     ULONG FirstDynamic;
    00820     ULONG LastEntry;
    00821     PMMWSL WorkingSetList;
    00822     PMMWSLE Wsle;
    00823     ULONG NumberOfCandidates;
    00824     PMMPTE PointerPte;
    00825     ULONG TheNextSlot;
    00826
    00827     WorkingSetList = WsInfo->VmWorkingSetList;
    00828     Wsle = WorkingSetList->Wsle;
    00829
    00830     //
    00831     // Toss a page out of the working set.
    00832     //
    00833
    00834     LastEntry = WorkingSetList->LastEntry;
    00835     FirstDynamic = WorkingSetList->FirstDynamic;
    00836     WorkingSetIndex = WorkingSetList->NextSlot;
    00837
    00838     if ((WorkingSetIndex > LastEntry) || (WorkingSetIndex < FirstDynamic)) {
    00839         WorkingSetIndex = FirstDynamic;
    00840     }
    00841
    00842     TheNextSlot = WorkingSetIndex;
    00843     NumberOfCandidates = 0;
    00844
    00845     do {
    00846
    00847         //
    00848         // Find a valid entry within the set.
    00849         //
    00850
    00851         if (Wsle[WorkingSetIndex].u1.e1.Valid != 0) {
    00852
    00853             PointerPte = MiGetPteAddress (
    00854                               Wsle[WorkingSetIndex].u1.VirtualAddress);
    00855
    00856             if ((MI_GET_ACCESSED_IN_PTE(PointerPte) == 0) ||
    00857                 (NumberOfCandidates > MM_WORKING_SET_LIST_SEARCH)) {
    00858
    00859                 PERFINFO_PAGE_INFO_REPLACEMENT_DECL();
    00860                 PERFINFO_GET_PAGE_INFO_REPLACEMENT(PointerPte);
    00861
    00862                 //
    00863                 // Don't pick the same entry we replaced the last time
    00864                 // unless we're under extreme pressure.
    00865                 //
    00866
    00867                 if ((WorkingSetIndex != TheNextSlot || MustReplace == TRUE) &&
    00868                     MiFreeWsle (WorkingSetIndex, WsInfo, PointerPte)) {
    00869
    00870                     PERFINFO_LOG_WS_REPLACEMENT(WsInfo);
    00871
    00872                     //
    00873                     // This entry was removed.
    00874                     //
    00875
    00876                     WorkingSetList->NextSlot = WorkingSetIndex + 1;
    00877                     break;
    00878                 }
    00879             }
    00880             MI_SET_ACCESSED_IN_PTE (PointerPte, 0);
    00881             NumberOfCandidates += 1;
    00882         }
    00883
    00884         WorkingSetIndex += 1;
    00885         if (WorkingSetIndex > LastEntry) {
    00886             WorkingSetIndex = FirstDynamic;
    00887         }
    00888
    00889     } while (WorkingSetIndex != TheNextSlot || MustReplace == TRUE);
    00890
    00891     //
    00892     // Entire working set list has been searched.  If an entry wasn't
    00893     // removed, our caller can increase the working set size.
    00894     //
    00895 }
    #endif

NTSTATUS MiSessionInitializeWorkingSetList | ( | VOID |  | ) |

Definition at line 1881 of file wslist.c.

References _MMSUPPORT::AllowWorkingSetAdjustment, ASSERT, BYTES_TO_PAGES, _MM_SESSION_SPACE::CommittedPages, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, DbgPrint, ExDeleteResource, ExInitializeResource, FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, _MMWSL::HashTableSize, _MMWSL::HashTableStart, _MMWSL::HighestPermittedHashAddress, Index, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_EXPANSION, LOCK_PFN, _MMSUPPORT::MaximumWorkingSetSize, MI_GET_PAGE_COLOR_FROM_VA, MI_NONPAGABLE_MEMORY_AVAILABLE, MI_PFN_ELEMENT, MI_SESSION_MAXIMUM_WORKING_SET, MI_SESSION_SPACE_WORKING_SET_MAXIMUM, MI_SESSION_SPACE_WORKING_SET_MINIMUM, MI_SESSION_SPACE_WS, MI_SESSION_VIEW_START, MI_SET_PTE_DIRTY, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiChargeCommitment(), MiEnsureAvailablePageOrWait(), MiFillMemoryPte, MiGetPdeAddress, MiGetPdeSessionIndex, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiGrowWsleHash(), MiInitializePfn(), MiInitializePfnForOtherProcess(), _MMSUPPORT::MinimumWorkingSetSize, MiRemoveAnyPage(), MiRemoveZeroPage(), MiRemoveZeroPageIfAny, MiReturnCommitment(), MiSessionWsList, MiZeroPhysicalPage(), MM_BUMP_COUNTER, MM_BUMP_SESS_COUNTER, MM_BUMP_SESSION_FAILURES, MM_DBG_COMMIT_RETURN_SESSION_WSL_FAILURE, MM_DBG_COMMIT_SESSION_WS_INIT, MM_DBG_SESSION_WS_PAGE_ALLOC, MM_DBG_SESSION_WS_PAGETABLE_ALLOC, MM_DEMAND_ZERO_WRITE_PTE, MM_FREE_WSLE_SHIFT, MM_SESSION_FAILURE_NO_COMMIT, MM_SESSION_FAILURE_NO_RESIDENT, MM_TRACK_COMMIT, MM_VA_MAPPED_BY_PDE, MmResidentAvailablePages, MmSessionSpace, _MMWSL::NextSlot, _MM_SESSION_SPACE::NonPagablePages, NULL, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, _MM_SESSION_SPACE::PagedPoolStart, _MM_SESSION_SPACE::PageTables, _MMWSL::Quota, SESSION_GLOBAL, _MM_SESSION_SPACE::SessionPageDirectoryIndex, TRUE, _MM_SESSION_SPACE::u, _MMSUPPORT::u, _MMPTE::u, _MMWSLE::u1, _MMPFN::u1, UNLOCK_EXPANSION, UNLOCK_PFN, _MMWSL::UsedPageTableEntries, ValidKernelPdeLocal, ValidKernelPteLocal, _MM_SESSION_SPACE::Vm, _MMSUPPORT::VmWorkingSetList, _MM_SESSION_SPACE::WorkingSetLockOwner, _MMSUPPORT::WorkingSetSize, _MMWSL::Wsle, _MM_SESSION_SPACE::Wsle, WSLE_NULL_INDEX, WSLE_NUMBER, _MM_SESSION_SPACE::WsListEntry, _MM_SESSION_SPACE::WsLock, and ZeroKernelPte.

Referenced by MmSessionCreate().

    01887                    :
    01888
    01889     This function initializes the working set for the session space and adds
    01890     it to the list of session space working sets.
    01891
    01892 Arguments:
    01893
    01894     None.
    01895
    01896 Return Value:
    01897
    01898     NT_SUCCESS if success or STATUS_NO_MEMORY on failure.
    01899
    01900 Environment:
    01901
    01902     Kernel mode, APC_LEVEL or below, no mutexes held.
    01903
    01904 --*/
    01905
    01906 {
    01907     ULONG i;
    01908     KIRQL OldIrql;
    01909     PMMPTE PointerPte;
    01910     PMMPTE PointerPde;
    01911     MMPTE  TempPte;
    01912     PMMWSLE WslEntry;
    01913     PMMPFN Pfn1;
    01914     ULONG PageColor;
    01915     PFN_NUMBER ResidentPages;
    01916     ULONG Index;
    01917     PFN_NUMBER PageFrameIndex;
    01918     ULONG CurrentEntry;
    01919     ULONG NumberOfEntriesMapped;
    01920     ULONG_PTR AdditionalBytes;
    01921     ULONG NumberOfEntriesMappedByFirstPage;
    01922     ULONG WorkingSetMaximum;
    01923     PMM_SESSION_SPACE SessionGlobal;
    01924     LOGICAL AllocatedPageTable;
    01925
    01926     //
    01927     // Use the global address for pointer references by
    01928     // MmWorkingSetManager before it attaches to the address space.
    01929     //
    01930
    01931     SessionGlobal = SESSION_GLOBAL (MmSessionSpace);
    01932
    01933     //
    01934     // Set up the working set variables.
    01935     //
    01936
    01937     WorkingSetMaximum = MI_SESSION_SPACE_WORKING_SET_MAXIMUM;
    01938
    01939     MmSessionSpace->Vm.VmWorkingSetList = (PMMWSL)MI_SESSION_SPACE_WS;
    01940 #if defined (_WIN64)
    01941     MmSessionSpace->Wsle = (PMMWSLE)(MmSessionSpace->Vm.VmWorkingSetList + 1);
    01942 #else
    01943     MmSessionSpace->Wsle =
    01944             (PMMWSLE)(&MmSessionSpace->Vm.VmWorkingSetList->UsedPageTableEntries[0]);
    01945 #endif
    01946
    01947     ASSERT (MmSessionSpace->WorkingSetLockOwner == NULL);
    01948     ASSERT (MmSessionSpace->WorkingSetLockOwnerCount == 0);
    01949
    01950     //
    01951     // Build the PDE entry for the working set - note that the global bit
    01952     // must be turned off.
    01953     //
    01954
    01955     PointerPde = MiGetPdeAddress (MmSessionSpace->Vm.VmWorkingSetList);
    01956
    01957     //
    01958     // The page table page for the working set and its first data page
    01959     // are charged against MmResidentAvailablePages and for commitment.
    01960     //
    01961
    01962     if (PointerPde->u.Hard.Valid == 1) {
    01963
    01964         //
    01965         // The page directory entry for the working set is the same
    01966         // as for another range in the session space.  Share the PDE.
    01967         //
    01968
    01969 #ifndef _IA64_
    01970         ASSERT (PointerPde->u.Hard.Global == 0);
    01971 #endif
    01972         AllocatedPageTable = FALSE;
    01973         ResidentPages = 1;
    01974     }
    01975     else {
    01976         AllocatedPageTable = TRUE;
    01977         ResidentPages = 2;
    01978     }
    01979
    01980
    01981     PointerPte = MiGetPteAddress (MmSessionSpace->Vm.VmWorkingSetList);
    01982
    01983     //
    01984     // The data pages needed to map up to maximum working set size are also
    01985     // charged against MmResidentAvailablePages and for commitment.
    01986     //
    01987
    01988     NumberOfEntriesMappedByFirstPage = (WSLE_NUMBER)(
    01989         ((PMMWSLE)((ULONG_PTR)MmSessionSpace->Vm.VmWorkingSetList + PAGE_SIZE)) -
    01990             MmSessionSpace->Wsle);
    01991
    01992     if (WorkingSetMaximum > NumberOfEntriesMappedByFirstPage) {
    01993         AdditionalBytes = (WorkingSetMaximum - NumberOfEntriesMappedByFirstPage) * sizeof (MMWSLE);
    01994         ResidentPages += BYTES_TO_PAGES (AdditionalBytes);
    01995     }
    01996
    01997     if (MiChargeCommitment (ResidentPages, NULL) == FALSE) {
    01998 #if DBG
    01999         DbgPrint("MiSessionInitializeWorkingSetList: No commit for %d pages\n",
    02000             ResidentPages);
    02001
    02002 #endif
    02003         MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_COMMIT);
    02004         return STATUS_NO_MEMORY;
    02005     }
    02006
    02007     MM_TRACK_COMMIT (MM_DBG_COMMIT_SESSION_WS_INIT, ResidentPages);
    02008
    02009     //
    02010     // Use the global address for resources since they are linked
    02011     // into the global system wide resource list.
    02012     //
    02013
    02014     ExInitializeResource (&SessionGlobal->WsLock);
    02015
    02016     LOCK_PFN (OldIrql);
    02017
    02018     //
    02019     // Check to make sure the physical pages are available.
    02020     //
    02021
    02022     if ((SPFN_NUMBER)ResidentPages > MI_NONPAGABLE_MEMORY_AVAILABLE() - 20) {
    02023 #if DBG
    02024         DbgPrint("MiSessionInitializeWorkingSetList: No Resident Pages %d, Need %d\n",
    02025             MmResidentAvailablePages,
    02026             ResidentPages);
    02027 #endif
    02028         UNLOCK_PFN (OldIrql);
    02029
    02030         MiReturnCommitment (ResidentPages);
    02031         MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_SESSION_WSL_FAILURE, ResidentPages);
    02032         ExDeleteResource (&SessionGlobal->WsLock);
    02033         MM_BUMP_SESSION_FAILURES (MM_SESSION_FAILURE_NO_RESIDENT);
    02034         return STATUS_NO_MEMORY;
    02035     }
    02036
    02037     MmResidentAvailablePages -= ResidentPages;
    02038
    02039     MM_BUMP_COUNTER(50, ResidentPages);
    02040
    02041     if (AllocatedPageTable == TRUE) {
    02042
    02043         MM_BUMP_SESS_COUNTER (MM_DBG_SESSION_WS_PAGETABLE_ALLOC, 1);
    02044
    02045         MiEnsureAvailablePageOrWait (NULL, NULL);
    02046
    02047         PageColor = MI_GET_PAGE_COLOR_FROM_VA (NULL);
    02048
    02049         PageFrameIndex = MiRemoveZeroPageIfAny (PageColor);
    02050         if (PageFrameIndex == 0) {
    02051             PageFrameIndex = MiRemoveAnyPage (PageColor);
    02052             UNLOCK_PFN (OldIrql);
    02053             MiZeroPhysicalPage (PageFrameIndex, PageColor);
    02054             LOCK_PFN (OldIrql);
    02055         }
    02056
    02057         //
    02058         // The global bit is masked off since we need to make sure the TB entry
    02059         // is flushed when we switch to a process in a different session space.
    02060         //
    02061
    02062         TempPte.u.Long = ValidKernelPdeLocal.u.Long;
    02063         TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    02064         MI_WRITE_VALID_PTE (PointerPde, TempPte);
    02065
    02066 #if !defined (_WIN64)
    02067
    02068         //
    02069         // Add this to the session structure so other processes can fault it in.
    02070         //
    02071
    02072         Index = MiGetPdeSessionIndex (MmSessionSpace->Vm.VmWorkingSetList);
    02073
    02074         MmSessionSpace->PageTables[Index] = TempPte;
    02075
    02076 #endif
    02077
    02078         //
    02079         // This page frame references the session space page table page.
    02080         //
    02081
    02082         MiInitializePfnForOtherProcess (PageFrameIndex,
    02083                                         PointerPde,
    02084                                         MmSessionSpace->SessionPageDirectoryIndex);
    02085
    02086         MiFillMemoryPte (PointerPte, PAGE_SIZE, ZeroKernelPte.u.Long);
    02087
    02088         Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    02089
    02090         //
    02091         // This page is never paged, ensure that its WsIndex stays clear so the
    02092         // release of the page will be handled correctly.
    02093         //
    02094
    02095         ASSERT (Pfn1->u1.WsIndex == 0);
    02096
    02097         KeFillEntryTb ((PHARDWARE_PTE) PointerPde, PointerPte, FALSE);
    02098     }
    02099
    02100     MiEnsureAvailablePageOrWait (NULL, NULL);
    02101
    02102     PageColor = MI_GET_PAGE_COLOR_FROM_VA (NULL);
    02103
    02104     PageFrameIndex = MiRemoveZeroPageIfAny (PageColor);
    02105     if (PageFrameIndex == 0) {
    02106         PageFrameIndex = MiRemoveAnyPage (PageColor);
    02107         UNLOCK_PFN (OldIrql);
    02108         MiZeroPhysicalPage (PageFrameIndex, PageColor);
    02109         LOCK_PFN (OldIrql);
    02110     }
    02111
    02112     MM_BUMP_SESS_COUNTER (MM_DBG_SESSION_WS_PAGE_ALLOC, ResidentPages - 1);
    02113
    02114 #if DBG
    02115     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    02116     ASSERT (Pfn1->u1.WsIndex == 0);
    02117 #endif
    02118
    02119     //
    02120     // The global bit is masked off since we need to make sure the TB entry
    02121     // is flushed when we switch to a process in a different session space.
    02122     //
    02123
    02124     TempPte.u.Long = ValidKernelPteLocal.u.Long;
    02125     MI_SET_PTE_DIRTY (TempPte);
    02126     TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    02127
    02128     MI_WRITE_VALID_PTE (PointerPte, TempPte);
    02129
    02130     MiInitializePfn (PageFrameIndex, PointerPte, 1);
    02131
    02132 #if DBG
    02133     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    02134     ASSERT (Pfn1->u1.WsIndex == 0);
    02135 #endif
    02136
    02137     UNLOCK_PFN (OldIrql);
    02138
    02139     KeFillEntryTb ((PHARDWARE_PTE) PointerPte,
    02140                    (PMMPTE)MmSessionSpace->Vm.VmWorkingSetList,
    02141                    FALSE);
    02142
    02143     //
    02144     // Fill in the reserved slots starting with the session data page.
    02145     //
    02146
    02147     WslEntry = MmSessionSpace->Wsle;
    02148
    02149     WslEntry->u1.VirtualAddress = (PVOID)MmSessionSpace;
    02150     WslEntry->u1.e1.Valid = 1;
    02151     WslEntry->u1.e1.LockedInWs = 1;
    02152     WslEntry->u1.e1.Direct = 1;
    02153
    02154     Pfn1 = MI_PFN_ELEMENT (MiGetPteAddress (WslEntry->u1.VirtualAddress)->u.Hard.PageFrameNumber);
    02155
    02156     ASSERT (Pfn1->u1.WsIndex == 0);
    02157
    02158     //
    02159     // The next reserved slot is for the page table page mapping
    02160     // the session data page.
    02161     //
    02162
    02163     WslEntry += 1;
    02164
    02165     WslEntry->u1.VirtualAddress = MiGetPteAddress (MmSessionSpace);
    02166     WslEntry->u1.e1.Valid = 1;
    02167     WslEntry->u1.e1.LockedInWs = 1;
    02168     WslEntry->u1.e1.Direct = 1;
    02169
    02170     Pfn1 = MI_PFN_ELEMENT (MiGetPteAddress (WslEntry->u1.VirtualAddress)->u.Hard.PageFrameNumber);
    02171
    02172     ASSERT (Pfn1->u1.WsIndex == 0);
    02173
    02174     CONSISTENCY_LOCK_PFN (OldIrql);
    02175
    02176     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmSessionSpace->Wsle);
    02177
    02178     CONSISTENCY_UNLOCK_PFN (OldIrql);
    02179
    02180     //
    02181     // The next reserved slot is for the working set page.
    02182     //
    02183
    02184     WslEntry += 1;
    02185
    02186     WslEntry->u1.VirtualAddress = MmSessionSpace->Vm.VmWorkingSetList;
    02187     WslEntry->u1.e1.Valid = 1;
    02188     WslEntry->u1.e1.LockedInWs = 1;
    02189     WslEntry->u1.e1.Direct = 1;
    02190
    02191     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    02192
    02193     ASSERT (Pfn1->u1.WsIndex == 0);
    02194
    02195     CONSISTENCY_LOCK_PFN (OldIrql);
    02196
    02197     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmSessionSpace->Wsle);
    02198
    02199     CONSISTENCY_UNLOCK_PFN (OldIrql);
    02200
    02201     if (AllocatedPageTable == TRUE) {
    02202
    02203         //
    02204         // The next reserved slot is for the page table page
    02205         // mapping the working set page.
    02206         //
    02207
    02208         WslEntry += 1;
    02209
    02210         WslEntry->u1.VirtualAddress = (PVOID)PointerPte;
    02211         WslEntry->u1.e1.Valid = 1;
    02212         WslEntry->u1.e1.LockedInWs = 1;
    02213         WslEntry->u1.e1.Direct = 1;
    02214
    02215         Pfn1 = MI_PFN_ELEMENT (MiGetPteAddress (WslEntry->u1.VirtualAddress)->u.Hard.PageFrameNumber);
    02216
    02217         ASSERT (Pfn1->u1.WsIndex == 0);
    02218
    02219         CONSISTENCY_LOCK_PFN (OldIrql);
    02220
    02221         Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmSessionSpace->Wsle);
    02222
    02223         CONSISTENCY_UNLOCK_PFN (OldIrql);
    02224     }
    02225
    02226     //
    02227     // The next reserved slot is for the page table page
    02228     // mapping the first session paged pool page.
    02229     //
    02230
    02231     WslEntry += 1;
    02232
    02233     WslEntry->u1.VirtualAddress = (PVOID)MiGetPteAddress (MmSessionSpace->PagedPoolStart);
    02234     WslEntry->u1.e1.Valid = 1;
    02235     WslEntry->u1.e1.LockedInWs = 1;
    02236     WslEntry->u1.e1.Direct = 1;
    02237
    02238     Pfn1 = MI_PFN_ELEMENT (MiGetPteAddress (WslEntry->u1.VirtualAddress)->u.Hard.PageFrameNumber);
    02239
    02240     ASSERT (Pfn1->u1.WsIndex == 0);
    02241
    02242     CONSISTENCY_LOCK_PFN (OldIrql);
    02243
    02244     Pfn1->u1.WsIndex = (WSLE_NUMBER)(WslEntry - MmSessionSpace->Wsle);
    02245
    02246     CONSISTENCY_UNLOCK_PFN (OldIrql);
    02247
    02248     CurrentEntry = (WSLE_NUMBER)(WslEntry + 1 - MmSessionSpace->Wsle);
    02249
    02250     MmSessionSpace->Vm.u.Flags.SessionSpace = 1;
    02251     MmSessionSpace->Vm.MinimumWorkingSetSize = MI_SESSION_SPACE_WORKING_SET_MINIMUM;
    02252     MmSessionSpace->Vm.MaximumWorkingSetSize = WorkingSetMaximum;
    02253
    02254     //
    02255     // Don't trim from this session till we're finished setting up and
    02256     // it's got some pages in it...
    02257     //
    02258
    02259     MmSessionSpace->Vm.AllowWorkingSetAdjustment = FALSE;
    02260
    02261     MmSessionSpace->Vm.VmWorkingSetList->LastEntry = MI_SESSION_SPACE_WORKING_SET_MINIMUM;
    02262     MmSessionSpace->Vm.VmWorkingSetList->Quota = MmSessionSpace->Vm.VmWorkingSetList->LastEntry;
    02263     MmSessionSpace->Vm.VmWorkingSetList->HashTable = NULL;
    02264     MmSessionSpace->Vm.VmWorkingSetList->HashTableSize = 0;
    02265     MmSessionSpace->Vm.VmWorkingSetList->Wsle = MmSessionSpace->Wsle;
    02266
    02267     MmSessionSpace->Vm.VmWorkingSetList->HashTableStart =
    02268        (PVOID)((PCHAR)PAGE_ALIGN (&MmSessionSpace->Wsle[MI_SESSION_MAXIMUM_WORKING_SET]) + PAGE_SIZE);
    02269
    02270 #if defined (_X86PAE_)
    02271
    02272     //
    02273     // One less page table page is needed on PAE systems.
    02274     //
    02275
    02276     MmSessionSpace->Vm.VmWorkingSetList->HighestPermittedHashAddress =
    02277         (PVOID)(MI_SESSION_VIEW_START - MM_VA_MAPPED_BY_PDE);
    02278 #else
    02279     MmSessionSpace->Vm.VmWorkingSetList->HighestPermittedHashAddress =
    02280         (PVOID)MI_SESSION_VIEW_START;
    02281 #endif
    02282
    02283     NumberOfEntriesMapped = (WSLE_NUMBER)(((PMMWSLE)((ULONG_PTR)MmSessionSpace->Vm.VmWorkingSetList +
    02284                                 PAGE_SIZE)) - MmSessionSpace->Wsle);
    02285
    02286     LOCK_PFN (OldIrql);
    02287
    02288     while (NumberOfEntriesMapped < WorkingSetMaximum) {
    02289
    02290         PointerPte += 1;
    02291
    02292         MiEnsureAvailablePageOrWait (NULL, NULL);
    02293
    02294         PageFrameIndex = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_VA (NULL));
    02295
    02296         PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE;
    02297
    02298         MiInitializePfn (PageFrameIndex, PointerPte, 1);
    02299
    02300         TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    02301
    02302         MI_SET_PTE_IN_WORKING_SET (&TempPte, CurrentEntry);
    02303
    02304         MI_WRITE_VALID_PTE (PointerPte, TempPte);
    02305
    02306         WslEntry += 1;
    02307
    02308         WslEntry->u1.VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte);
    02309         WslEntry->u1.e1.Valid = 1;
    02310         WslEntry->u1.e1.LockedInWs = 1;
    02311         WslEntry->u1.e1.Direct = 1;
    02312
    02313         Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    02314
    02315         ASSERT (Pfn1->u1.WsIndex == 0);
    02316         Pfn1->u1.WsIndex = CurrentEntry;
    02317
    02318         // MiInsertWsle(CurrentEntry, MmWorkingSetList);
    02319
    02320         CurrentEntry += 1;
    02321
    02322         NumberOfEntriesMapped += PAGE_SIZE / sizeof(MMWSLE);
    02323     }
    02324
    02325     UNLOCK_PFN (OldIrql);
    02326
    02327     MmSessionSpace->Vm.WorkingSetSize = CurrentEntry;
    02328     MmSessionSpace->Vm.VmWorkingSetList->FirstFree = CurrentEntry;
    02329     MmSessionSpace->Vm.VmWorkingSetList->FirstDynamic = CurrentEntry;
    02330     MmSessionSpace->Vm.VmWorkingSetList->NextSlot = CurrentEntry;
    02331
    02332     MmSessionSpace->NonPagablePages += ResidentPages;
    02333     MmSessionSpace->CommittedPages += ResidentPages;
    02334
    02335     //
    02336     // Initialize the following slots as free.
    02337     //
    02338
    02339     WslEntry = MmSessionSpace->Wsle + CurrentEntry;
    02340
    02341     for (i = CurrentEntry + 1; i < NumberOfEntriesMapped; i += 1) {
    02342
    02343         //
    02344         // Build the free list, note that the first working
    02345         // set entries (CurrentEntry) are not on the free list.
    02346         // These entries are reserved for the pages which
    02347         // map the working set and the page which contains the PDE.
    02348         //
    02349
    02350         WslEntry->u1.Long = i << MM_FREE_WSLE_SHIFT;
    02351         WslEntry += 1;
    02352     }
    02353
    02354     WslEntry->u1.Long = WSLE_NULL_INDEX << MM_FREE_WSLE_SHIFT;  // End of list.
    02355
    02356     MmSessionSpace->Vm.VmWorkingSetList->LastInitializedWsle = NumberOfEntriesMapped - 1;
    02357
    02358     if (WorkingSetMaximum > ((1536*1024) >> PAGE_SHIFT)) {
    02359
    02360         //
    02361         // The working set list consists of more than a single page.
    02362         //
    02363
    02364         MiGrowWsleHash (&MmSessionSpace->Vm);
    02365     }
    02366
    02367     //
    02368     // Put this session's working set in lists using its global address.
    02369     //
    02370
    02371     LOCK_EXPANSION (OldIrql);
    02372
    02373     InsertTailList (&MiSessionWsList, &SessionGlobal->WsListEntry);
    02374
    02375     MmSessionSpace->u.Flags.HasWsLock = 1;
    02376
    02377     MmSessionSpace->u.Flags.SessionListInserted = 1;
    02378
    02379     UNLOCK_EXPANSION (OldIrql);
    02380
    02381     return STATUS_SUCCESS;
    02382 }

ULONG MiTrimWorkingSet | ( | ULONG | Reduction,
|  | IN PMMSUPPORT | WsInfo,
|  | IN ULONG | ForcedReductionOrTrimAge
| ) |

Definition at line 3612 of file wslist.c.

References FALSE, _MMWSL::FirstDynamic, _MMWSL::LastEntry, MI_GET_ACCESSED_IN_PTE, MI_GET_WSLE_AGE, MI_SET_ACCESSED_IN_PTE, MiFreeWsle(), MiGetPteAddress, MiRemoveWorkingSetPages(), MM_SYSTEM_WS_LOCK_ASSERT, MmSystemCacheWs, _MMWSL::NextSlot, PAGE_SIZE, PERFINFO_GET_PAGE_INFO_WITH_DECL, PERFINFO_LOG_WS_REMOVAL, _MMWSL::Quota, TRUE, _MMSUPPORT::u, _MMWSLE::u1, _MMWSLE::VirtualAddress, and _MMWSL::Wsle.

Referenced by MiDoReplacement(), MmSetMemoryPriorityProcess(), and MmWorkingSetManager().

    03620                    :
    03621
    03622     This function reduces the working set by the specified amount.
    03623
    03624 Arguments:
    03625
    03626     Reduction - Supplies the number of pages to remove from the working
    03627                 set.
    03628
    03629     WsInfo - Supplies a pointer to the working set information for the
    03630              process (or system cache) to trim.
    03631
    03632     ForcedReductionOrTrimAge - If using fault-based trimming, this is set to
    03633                                TRUE if the reduction is being done to free up
    03634                                pages in which case we should try to reduce
    03635                                working set pages as well.  Set to FALSE when
    03636                                the reduction is trying to increase the fault
    03637                                rates in which case the policy should be more
    03638                                like locate and reserve.
    03639
    03640                                If using claim-based trimming, this is the age
    03641                                value to use - ie: pages of this age or older
    03642                                will be removed.
    03643
    03644 Return Value:
    03645
    03646     Returns the actual number of pages removed.
    03647
    03648 Environment:
    03649
    03650     Kernel mode, APCs disabled, working set lock.  PFN lock NOT held.
    03651
    03652 --*/
    03653
    03654 {
    03655     ULONG TryToFree;
    03656     ULONG StartEntry;
    03657     ULONG LastEntry;
    03658     PMMWSL WorkingSetList;
    03659     PMMWSLE Wsle;
    03660     PMMPTE PointerPte;
    03661     ULONG NumberLeftToRemove;
    03662     ULONG LoopCount;
    03663     ULONG EndCount;
    03664     BOOLEAN StartFromZero;
    03665
    03666     NumberLeftToRemove = Reduction;
    03667     WorkingSetList = WsInfo->VmWorkingSetList;
    03668     Wsle = WorkingSetList->Wsle;
    03669
    03670 #if DBG
    03671     if (WsInfo == &MmSystemCacheWs) {
    03672         MM_SYSTEM_WS_LOCK_ASSERT();
    03673     }
    03674 #endif //DBG
    03675
    03676     LastEntry = WorkingSetList->LastEntry;
    03677
    03678     TryToFree = WorkingSetList->NextSlot;
    03679     if (TryToFree > LastEntry || TryToFree < WorkingSetList->FirstDynamic) {
    03680         TryToFree = WorkingSetList->FirstDynamic;
    03681     }
    03682
    03683     StartEntry = TryToFree;
    03684
    03685 #ifdef _MI_USE_CLAIMS_
    03686
    03687     while (NumberLeftToRemove != 0) {
    03688         if (Wsle[TryToFree].u1.e1.Valid == 1) {
    03689             PointerPte = MiGetPteAddress (Wsle[TryToFree].u1.VirtualAddress);
    03690
    03691             if ((ForcedReductionOrTrimAge == 0) ||
    03692                 ((MI_GET_ACCESSED_IN_PTE (PointerPte) == 0) &&
    03693                 (MI_GET_WSLE_AGE(PointerPte, &Wsle[TryToFree]) >= ForcedReductionOrTrimAge))) {
    03694
    03695                 PERFINFO_GET_PAGE_INFO_WITH_DECL(PointerPte);
    03696
    03697                 if (MiFreeWsle (TryToFree, WsInfo, PointerPte)) {
    03698                     PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_VOLUNTRIM, WsInfo);
    03699                     NumberLeftToRemove -= 1;
    03700                 }
    03701             }
    03702         }
    03703         TryToFree += 1;
    03704
    03705         if (TryToFree > LastEntry) {
    03706             TryToFree = WorkingSetList->FirstDynamic;
    03707         }
    03708
    03709         if (TryToFree == StartEntry) {
    03710             break;
    03711         }
    03712     }
    03713
    03714 #else
    03715
    03716     LoopCount = 0;
    03717
    03718     if (ForcedReductionOrTrimAge) {
    03719         EndCount = 4;
    03720     } else {
    03721         EndCount = 1;
    03722     }
    03723
    03724     StartFromZero = FALSE;
    03725
    03726     while (NumberLeftToRemove != 0 && LoopCount != EndCount) {
    03727         while ((NumberLeftToRemove != 0) && (TryToFree <= LastEntry)) {
    03728
    03729             if (Wsle[TryToFree].u1.e1.Valid == 1) {
    03730                 PointerPte = MiGetPteAddress (Wsle[TryToFree].u1.VirtualAddress);
    03731                 if (MI_GET_ACCESSED_IN_PTE (PointerPte)) {
    03732
    03733                     //
    03734                     // If accessed bit is set, clear it.  If accessed
    03735                     // bit is clear, remove from working set.
    03736                     //
    03737
    03738                     MI_SET_ACCESSED_IN_PTE (PointerPte, 0);
    03739                 } else {
    03740                     PERFINFO_GET_PAGE_INFO_WITH_DECL(PointerPte);
    03741                     if (MiFreeWsle (TryToFree, WsInfo, PointerPte)) {
    03742                         PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_VOLUNTRIM, WsInfo);
    03743                         NumberLeftToRemove -= 1;
    03744                     }
    03745                 }
    03746             }
    03747             TryToFree += 1;
    03748
    03749             if (StartFromZero == TRUE && EndCount == 1 && TryToFree >= StartEntry) {
    03750                 LoopCount = EndCount;
    03751                 if (TryToFree > LastEntry) {
    03752                     TryToFree = WorkingSetList->FirstDynamic;
    03753                 }
    03754                 break;
    03755             }
    03756         }
    03757
    03758         if (TryToFree > LastEntry) {
    03759             TryToFree = WorkingSetList->FirstDynamic;
    03760             if (StartFromZero == TRUE) {
    03761
    03762                 //
    03763                 // We've already wrapped once but didn't get back to
    03764                 // the StartEntry.  Use the first dynamic as our base now.
    03765                 //
    03766
    03767                 StartEntry = TryToFree;
    03768             }
    03769             else {
    03770                 StartFromZero = TRUE;
    03771             }
    03772
    03773             if (TryToFree >= StartEntry) {
    03774
    03775                 //
    03776                 // We've wrapped. If this is not a forced trim, then bail
    03777                 // now so we don't cannibalize entries we just cleared the
    03778                 // access bit for because they haven't had a fair chance to
    03779                 // be re-accessed yet.
    03780                 //
    03781
    03782                 LoopCount += 1;
    03783                 StartFromZero = FALSE;
    03784             }
    03785         }
    03786     }
    03787
    03788 #endif
    03789
    03790     WorkingSetList->NextSlot = TryToFree;
    03791
    03792     //
    03793     // If this is not the system cache or a session working set, see if the
    03794     // working set list can be contracted.
    03795     //
    03796
    03797     if (WsInfo != &MmSystemCacheWs && WsInfo->u.Flags.SessionSpace == 0) {
    03798
    03799         //
    03800         // Make sure we are at least a page above the working set maximum.
    03801         //
    03802
    03803         if (WorkingSetList->FirstDynamic == WsInfo->WorkingSetSize) {
    03804                 MiRemoveWorkingSetPages (WorkingSetList, WsInfo);
    03805         } else {
    03806
    03807             if ((WorkingSetList->Quota + 15 + (PAGE_SIZE / sizeof(MMWSLE))) <
    03808                                                     WorkingSetList->LastEntry) {
    03809                 if ((WsInfo->MaximumWorkingSetSize + 15 + (PAGE_SIZE / sizeof(MMWSLE))) <
    03810                      WorkingSetList->LastEntry ) {
    03811                     MiRemoveWorkingSetPages (WorkingSetList, WsInfo);
    03812                 }
    03813             }
    03814         }
    03815     }
    03816     return Reduction - NumberLeftToRemove;
    03817 }

VOID MiUpdateWsle | ( | IN OUT PWSLE_NUMBER | DesiredIndex,
|  | IN PVOID | VirtualAddress,
|  | PMMWSL | WorkingSetList,
|  | IN PMMPFN | Pfn
| ) |

Definition at line 1078 of file wslist.c.

References ASSERT, ASSERT32, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, Index, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, MI_IS_SESSION_ADDRESS, MI_IS_SYSTEM_CACHE_ADDRESS, MI_ZERO_WSINDEX, MiInsertWsle(), MiSwapWslEntries(), MM_FREE_WSLE_SHIFT, MM_PAGED_POOL_START, MM_SYSTEM_SPACE_START, MM_SYSTEM_WS_LOCK_ASSERT, MmNonPagedSystemStart, MmPagedPoolPage, MmSessionSpace, MmSystemCachePage, MmSystemCacheStart, MmSystemCacheWorkingSetList, MmSystemCacheWs, MmSystemCacheWsle, MmSystemCodePage, MmSystemDriverPage, MmWsle, NULL, PAGE_ALIGN, PAGE_SIZE, PsGetCurrentProcess, PsGetCurrentThread, PWSLE_NUMBER, _MMWSLE::u1, _MM_SESSION_SPACE::Vm, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MiAddValidPageToWorkingSet(), MiAddWorkingSetPage(), MiAddWsleHash(), MiLockCode(), MmAccessFault(), MmCheckCachedPageState(), and MmCopyToCachedPage().

    01087                    :
    01088
    01089     This routine updates a reserved working set entry to place it into
    01090     the valid state.
    01091
    01092 Arguments:
    01093
    01094     DesiredIndex - Supplies the index of the working set entry to update.
    01095
    01096     VirtualAddress - Supplies the virtual address which the working set
    01097                      entry maps.
    01098
    01099     WsInfo - Supplies a pointer to the working set info block for the
    01100              process (or system cache).
    01101
    01102     Pfn - Supplies a pointer to the PFN element for the page.
    01103
    01104 Return Value:
    01105
    01106     None.
    01107
    01108 Environment:
    01109
    01110     Kernel mode, APCs disabled, working set lock held and PFN lock held.
    01111
    01112 --*/
    01113
    01114 {
    01115     PMMWSLE Wsle;
    01116     WSLE_NUMBER Index;
    01117     WSLE_NUMBER WorkingSetIndex;
    01118 #if PFN_CONSISTENCY
    01119     KIRQL OldIrql;
    01120 #endif
    01121
    01122     WorkingSetIndex = *DesiredIndex;
    01123     Wsle = WorkingSetList->Wsle;
    01124
    01125     if (WorkingSetList == MmSystemCacheWorkingSetList) {
    01126
    01127         //
    01128         // This assert doesn't hold for NT64 as we can be adding page
    01129         // directories and page tables for the system cache WSLE hash tables.
    01130         //
    01131
    01132         ASSERT32 ((VirtualAddress < (PVOID)PTE_BASE) ||
    01133                   (VirtualAddress >= (PVOID)MM_SYSTEM_SPACE_START));
    01134     } else {
    01135         ASSERT ((VirtualAddress < (PVOID)MM_SYSTEM_SPACE_START) ||
    01136                (MI_IS_SESSION_ADDRESS (VirtualAddress)));
    01137     }
    01138
    01139     ASSERT (WorkingSetIndex >= WorkingSetList->FirstDynamic);
    01140
    01141     if (WorkingSetList == MmSystemCacheWorkingSetList) {
    01142
    01143         MM_SYSTEM_WS_LOCK_ASSERT();
    01144
    01145         //
    01146         // count system space inserts and removals.
    01147         //
    01148
    01149 #if defined(_X86_)
    01150         if (MI_IS_SYSTEM_CACHE_ADDRESS(VirtualAddress)) {
    01151             MmSystemCachePage += 1;
    01152         } else
    01153 #endif
    01154         if (VirtualAddress < MmSystemCacheStart) {
    01155             MmSystemCodePage += 1;
    01156         } else if (VirtualAddress < MM_PAGED_POOL_START) {
    01157             MmSystemCachePage += 1;
    01158         } else if (VirtualAddress < MmNonPagedSystemStart) {
    01159             MmPagedPoolPage += 1;
    01160         } else {
    01161             MmSystemDriverPage += 1;
    01162         }
    01163     }
    01164
    01165     //
    01166     // Make the wsle valid, referring to the corresponding virtual
    01167     // page number.
    01168     //
    01169
    01170     //
    01171     // The value 0 is invalid.  This is due to the fact that the working
    01172     // set lock is a process wide lock and two threads in different
    01173     // processes could be adding the same physical page to their working
    01174     // sets.  Each one could see the WsIndex field in the PFN as 0, and
    01175     // set the direct bit.  To solve this, the WsIndex field is set to
    01176     // the current thread pointer.
    01177     //
    01178
    01179     ASSERT (Pfn->u1.WsIndex != 0);
    01180
    01181 #if DBG
    01182     if (Pfn->u1.WsIndex <= WorkingSetList->LastInitializedWsle) {
    01183         ASSERT ((PAGE_ALIGN(VirtualAddress) !=
    01184                 PAGE_ALIGN(Wsle[Pfn->u1.WsIndex].u1.VirtualAddress)) ||
    01185                 (Wsle[Pfn->u1.WsIndex].u1.e1.Valid == 0));
    01186     }
    01187 #endif //DBG
    01188
    01189     Wsle[WorkingSetIndex].u1.VirtualAddress = VirtualAddress;
    01190     Wsle[WorkingSetIndex].u1.Long &= ~(PAGE_SIZE - 1);
    01191     Wsle[WorkingSetIndex].u1.e1.Valid = 1;
    01192
    01193     if ((ULONG_PTR)Pfn->u1.Event == (ULONG_PTR)PsGetCurrentThread()) {
    01194
    01195         //
    01196         // Directly index into the WSL for this entry via the PFN database
    01197         // element.
    01198         //
    01199
    01200         CONSISTENCY_LOCK_PFN (OldIrql);
    01201
    01202 #if defined(_WIN64)
    01203
    01204         //
    01205         // The entire working set index union must be zeroed on Win64 systems.
    01206         //
    01207
    01208         MI_ZERO_WSINDEX (Pfn);
    01209
    01210 #endif
    01211
    01212         Pfn->u1.WsIndex = WorkingSetIndex;
    01213
    01214         CONSISTENCY_UNLOCK_PFN (OldIrql);
    01215
    01216         Wsle[WorkingSetIndex].u1.e1.Direct = 1;
    01217
    01218         return;
    01219
    01220     } else if (WorkingSetList->HashTable == NULL) {
    01221
    01222         //
    01223         // Try to insert at WsIndex.
    01224         //
    01225
    01226         Index = Pfn->u1.WsIndex;
    01227
    01228         if ((Index < WorkingSetList->LastInitializedWsle) &&
    01229             (Index > WorkingSetList->FirstDynamic) &&
    01230             (Index != WorkingSetIndex)) {
    01231
    01232             if (Wsle[Index].u1.e1.Valid) {
    01233
    01234                 if (Wsle[Index].u1.e1.Direct) {
    01235
    01236                     //
    01237                     // Only move direct indexed entries.
    01238                     //
    01239
    01240                     PMMSUPPORT WsInfo;
    01241
    01242                     if (Wsle == MmWsle) {
    01243                         WsInfo = &PsGetCurrentProcess()->Vm;
    01244                     }
    01245                     else if (Wsle == MmSystemCacheWsle) {
    01246                         WsInfo = &MmSystemCacheWs;
    01247                     }
    01248                     else {
    01249                         WsInfo = &MmSessionSpace->Vm;
    01250                     }
    01251
    01252                     MiSwapWslEntries (Index, WorkingSetIndex, WsInfo);
    01253                     WorkingSetIndex = Index;
    01254                 }
    01255             } else {
    01256
    01257                 //
    01258                 // On free list, try to remove quickly without walking
    01259                 // all the free pages.
    01260                 //
    01261
    01262                 ULONG FreeIndex;
    01263                 MMWSLE Temp;
    01264
    01265                 FreeIndex = 0;
    01266
    01267                 ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
    01268                 ASSERT (WorkingSetIndex >= WorkingSetList->FirstDynamic);
    01269
    01270                 if (WorkingSetList->FirstFree == Index) {
    01271                     WorkingSetList->FirstFree = WorkingSetIndex;
    01272                     Temp = Wsle[WorkingSetIndex];
    01273                     Wsle[WorkingSetIndex] = Wsle[Index];
    01274                     Wsle[Index] = Temp;
    01275                     WorkingSetIndex = Index;
    01276                     ASSERT (((Wsle[WorkingSetList->FirstFree].u1.Long >> MM_FREE_WSLE_SHIFT)
    01277                                      <= WorkingSetList->LastInitializedWsle) ||
    01278                             ((Wsle[WorkingSetList->FirstFree].u1.Long >> MM_FREE_WSLE_SHIFT)
    01279                                     == WSLE_NULL_INDEX));
    01280                 } else if (Wsle[Index - 1].u1.e1.Valid == 0) {
    01281                     if ((Wsle[Index - 1].u1.Long >> MM_FREE_WSLE_SHIFT) == Index) {
    01282                         FreeIndex = Index - 1;
    01283                     }
    01284                 } else if (Wsle[Index + 1].u1.e1.Valid == 0) {
    01285                     if ((Wsle[Index + 1].u1.Long >> MM_FREE_WSLE_SHIFT) == Index) {
    01286                         FreeIndex = Index + 1;
    01287                     }
    01288                 }
    01289                 if (FreeIndex != 0) {
    01290
    01291                     //
    01292                     // Link the Wsle into the free list.
    01293                     //
    01294
    01295                     Temp = Wsle[WorkingSetIndex];
    01296                     Wsle[FreeIndex].u1.Long = WorkingSetIndex << MM_FREE_WSLE_SHIFT;
    01297                     Wsle[WorkingSetIndex] = Wsle[Index];
    01298                     Wsle[Index] = Temp;
    01299                     WorkingSetIndex = Index;
    01300
    01301                     ASSERT (((Wsle[FreeIndex].u1.Long >> MM_FREE_WSLE_SHIFT)
    01302                                      <= WorkingSetList->LastInitializedWsle) ||
    01303                             ((Wsle[FreeIndex].u1.Long >> MM_FREE_WSLE_SHIFT)
    01304                                     == WSLE_NULL_INDEX));
    01305                 }
    01306
    01307             }
    01308             *DesiredIndex = WorkingSetIndex;
    01309
    01310             if (WorkingSetIndex > WorkingSetList->LastEntry) {
    01311                 WorkingSetList->LastEntry = WorkingSetIndex;
    01312             }
    01313         }
    01314     }
    01315
    01316     //
    01317     // Insert the valid WSLE into the working set list.
    01318     //
    01319
    01320     MiInsertWsle (WorkingSetIndex, WorkingSetList);
    01321     return;
    01322 }

NTSTATUS MmAdjustWorkingSetSize | ( | IN SIZE_T | WorkingSetMinimumInBytes,
|  | IN SIZE_T | WorkingSetMaximumInBytes,
|  | IN ULONG | SystemCache
| ) |

Definition at line 2450 of file wslist.c.

References _EPROCESS::AddressSpaceDeleted, _MMSUPPORT::AllowWorkingSetAdjustment, ASSERT, ExPageLockHandle, FALSE, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_PFN, LOCK_SYSTEM_WS, LOCK_WS, _MMSUPPORT::MaximumWorkingSetSize, MI_NONPAGABLE_MEMORY_AVAILABLE, MiAddWorkingSetPage(), MiEmptyWorkingSet(), MiFreeWsle(), MiGetPteAddress, MiGrowWsleHash(), _MMSUPPORT::MinimumWorkingSetSize, MM_BUMP_COUNTER, MM_FLUID_WORKING_SET, MM_RETRY_COUNT, MmAllowWorkingSetExpansion(), MmAvailablePages, MmLockPagableSectionByHandle(), MmMaximumWorkingSetSize, MmMinimumWorkingSetSize, MmPagesAboveWsMinimum, MmResidentAvailablePages, MmSystemCacheWs, MmUnlockPagableImageSection(), NTSTATUS(), NULL, PAGE_SHIFT, PAGE_SIZE, PERFINFO_GET_PAGE_INFO, PERFINFO_LOG_WS_REMOVAL, PERFINFO_PAGE_INFO_DECL, PsGetCurrentProcess, _MMWSL::Quota, TRUE, _MMWSLE::u1, UNLOCK_PFN, UNLOCK_SYSTEM_WS, UNLOCK_WS, _MMWSLE::VirtualAddress, _EPROCESS::Vm, _MMSUPPORT::VmWorkingSetList, _MMSUPPORT::WorkingSetSize, _MMWSL::Wsle, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by NtSetInformationJobObject(), NtSetSystemInformation(), PspAddProcessToJob(), PspSetQuotaLimits(), and xxxMinMaximize().

    02458                    :
    02459
    02460     This routine adjusts the current size of a process's working set
    02461     list.  If the maximum value is above the current maximum, pages
    02462     are removed from the working set list.
    02463
    02464     An exception is raised if the limit cannot be granted.  This
    02465     could occur if too many pages were locked in the process's
    02466     working set.
    02467
    02468     Note: if the minimum and maximum are both (SIZE_T)-1, the working set
    02469           is purged, but the default sizes are not changed.
    02470
    02471 Arguments:
    02472
    02473     WorkingSetMinimumInBytes - Supplies the new minimum working set size in
    02474                                bytes.
    02475
    02476     WorkingSetMaximumInBytes - Supplies the new maximum working set size in
    02477                                bytes.
    02478
    02479     SystemCache - Supplies TRUE if the system cache working set is being
    02480                   adjusted, FALSE for all other working sets.
    02481
    02482 Return Value:
    02483
    02484     NTSTATUS.
    02485
    02486 Environment:
    02487
    02488     Kernel mode, IRQL APC_LEVEL or below.
    02489
    02490 --*/
    02491
    02492
    02493 {
    02494     PEPROCESS CurrentProcess;
    02495     ULONG Entry;
    02496     ULONG LastFreed;
    02497     PMMWSLE Wsle;
    02498     KIRQL OldIrql;
    02499     KIRQL OldIrql2;
    02500     SPFN_NUMBER i;
    02501     PMMPTE PointerPte;
    02502     NTSTATUS ReturnStatus;
    02503     LONG PagesAbove;
    02504     LONG NewPagesAbove;
    02505     ULONG FreeTryCount;
    02506     PMMSUPPORT WsInfo;
    02507     PMMWSL WorkingSetList;
    02508     WSLE_NUMBER WorkingSetMinimum;
    02509     WSLE_NUMBER WorkingSetMaximum;
    02510
    02511     PERFINFO_PAGE_INFO_DECL();
    02512
    02513     FreeTryCount = 0;
    02514
    02515     if (SystemCache) {
    02516         WsInfo = &MmSystemCacheWs;
    02517     } else {
    02518         CurrentProcess = PsGetCurrentProcess ();
    02519         WsInfo = &CurrentProcess->Vm;
    02520     }
    02521
    02522     if ((WorkingSetMinimumInBytes == (SIZE_T)-1) &&
    02523         (WorkingSetMaximumInBytes == (SIZE_T)-1)) {
    02524         return MiEmptyWorkingSet (WsInfo, TRUE);
    02525     }
    02526
    02527     if (WorkingSetMinimumInBytes == 0) {
    02528         WorkingSetMinimum = WsInfo->MinimumWorkingSetSize;
    02529     }
    02530     else {
    02531         WorkingSetMinimum = (WSLE_NUMBER)(WorkingSetMinimumInBytes >> PAGE_SHIFT);
    02532     }
    02533
    02534     if (WorkingSetMaximumInBytes == 0) {
    02535         WorkingSetMaximum = WsInfo->MaximumWorkingSetSize;
    02536     }
    02537     else {
    02538         WorkingSetMaximum = (WSLE_NUMBER)(WorkingSetMaximumInBytes >> PAGE_SHIFT);
    02539     }
    02540
    02541     if (WorkingSetMinimum > WorkingSetMaximum) {
    02542         return STATUS_BAD_WORKING_SET_LIMIT;
    02543     }
    02544
    02545     MmLockPagableSectionByHandle(ExPageLockHandle);
    02546
    02547     ReturnStatus = STATUS_SUCCESS;
    02548
    02549     //
    02550     // Get the working set lock and disable APCs.
    02551     //
    02552
    02553     if (SystemCache) {
    02554         LOCK_SYSTEM_WS (OldIrql2);
    02555     } else {
    02556         LOCK_WS (CurrentProcess);
    02557
    02558         if (CurrentProcess->AddressSpaceDeleted != 0) {
    02559             ReturnStatus = STATUS_PROCESS_IS_TERMINATING;
    02560             goto Returns;
    02561         }
    02562     }
    02563
    02564     if (WorkingSetMaximum > MmMaximumWorkingSetSize) {
    02565         WorkingSetMaximum = MmMaximumWorkingSetSize;
    02566         ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
    02567     }
    02568
    02569     if (WorkingSetMinimum > MmMaximumWorkingSetSize) {
    02570         WorkingSetMinimum = MmMaximumWorkingSetSize;
    02571         ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
    02572     }
    02573
    02574     if (WorkingSetMinimum < MmMinimumWorkingSetSize) {
    02575         WorkingSetMinimum = (ULONG)MmMinimumWorkingSetSize;
    02576         ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
    02577     }
    02578
    02579     //
    02580     // Make sure that the number of locked pages will not
    02581     // make the working set not fluid.
    02582     //
    02583
    02584     if ((WsInfo->VmWorkingSetList->FirstDynamic + MM_FLUID_WORKING_SET) >=
    02585          WorkingSetMaximum) {
    02586         ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
    02587         goto Returns;
    02588     }
    02589
    02590     WorkingSetList = WsInfo->VmWorkingSetList;
    02591     Wsle = WorkingSetList->Wsle;
    02592
    02593     //
    02594     // Check to make sure ample resident physical pages exist for
    02595     // this operation.
    02596     //
    02597
    02598     LOCK_PFN (OldIrql);
    02599
    02600     i = WorkingSetMinimum - WsInfo->MinimumWorkingSetSize;
    02601
    02602     if (i > 0) {
    02603
    02604         //
    02605         // New minimum working set is greater than the old one.  Ensure that
    02606         // we don't allow this process' working set minimum to increase to
    02607         // a point where subsequent nonpaged pool allocations could cause
    02608         // us to run out of pages.  Additionally, leave 100 extra pages around
    02609         // so the user can later bring up tlist and kill processes if necessary.
    02610         //
    02611
    02612         if (MmAvailablePages < (20 + (i / (PAGE_SIZE / sizeof (MMWSLE))))) {
    02613             UNLOCK_PFN (OldIrql);
    02614             ReturnStatus = STATUS_INSUFFICIENT_RESOURCES;
    02615             goto Returns;
    02616         }
    02617
    02618         if (MI_NONPAGABLE_MEMORY_AVAILABLE() - 100 < i) {
    02619             UNLOCK_PFN (OldIrql);
    02620             ReturnStatus = STATUS_INSUFFICIENT_RESOURCES;
    02621             goto Returns;
    02622         }
    02623     }
    02624
    02625     //
    02626     // Adjust the number of resident pages up or down dependent on
    02627     // the size of the new minimum working set size versus the previous
    02628     // minimum size.
    02629     //
    02630
    02631     MmResidentAvailablePages -= i;
    02632     MM_BUMP_COUNTER(27, i);
    02633
    02634     UNLOCK_PFN (OldIrql);
    02635
    02636     if (WsInfo->AllowWorkingSetAdjustment == FALSE) {
    02637         MmAllowWorkingSetExpansion ();
    02638     }
    02639
    02640     if (WorkingSetMaximum > WorkingSetList->LastInitializedWsle) {
    02641
    02642          do {
    02643
    02644             //
    02645             // The maximum size of the working set is being increased, check
    02646             // to ensure the proper number of pages are mapped to cover
    02647             // the complete working set list.
    02648             //
    02649
    02650             if (!MiAddWorkingSetPage (WsInfo)) {
    02651                 WorkingSetMaximum = WorkingSetList->LastInitializedWsle - 1;
    02652                 break;
    02653             }
    02654         } while (WorkingSetMaximum > WorkingSetList->LastInitializedWsle);
    02655
    02656     } else {
    02657
    02658         //
    02659         // The new working set maximum is less than the current working set
    02660         // maximum.
    02661         //
    02662
    02663         if (WsInfo->WorkingSetSize > WorkingSetMaximum) {
    02664
    02665             //
    02666             // Remove some pages from the working set.
    02667             //
    02668
    02669             //
    02670             // Make sure that the number of locked pages will not
    02671             // make the working set not fluid.
    02672             //
    02673
    02674             if ((WorkingSetList->FirstDynamic + MM_FLUID_WORKING_SET) >=
    02675                  WorkingSetMaximum) {
    02676
    02677                 ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
    02678
    02679                 LOCK_PFN (OldIrql);
    02680
    02681                 MmResidentAvailablePages += i;
    02682                 MM_BUMP_COUNTER(54, i);
    02683
    02684                 UNLOCK_PFN (OldIrql);
    02685
    02686                 goto Returns;
    02687             }
    02688
    02689             //
    02690             // Attempt to remove the pages from the Maximum downward.
    02691             //
    02692
    02693             LastFreed = WorkingSetList->LastEntry;
    02694             if (WorkingSetList->LastEntry > WorkingSetMaximum) {
    02695
    02696                 while (LastFreed >= WorkingSetMaximum) {
    02697
    02698                     PointerPte = MiGetPteAddress(
    02699                                         Wsle[LastFreed].u1.VirtualAddress);
    02700
    02701                     PERFINFO_GET_PAGE_INFO(PointerPte);
    02702
    02703                     if ((Wsle[LastFreed].u1.e1.Valid != 0) &&
    02704                         (!MiFreeWsle (LastFreed,
    02705                                       WsInfo,
    02706                                       PointerPte))) {
    02707
    02708                         //
    02709                         // This LastFreed could not be removed.
    02710                         //
    02711
    02712                         break;
    02713                     }
    02714                     PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_ADJUSTWS, WsInfo);
    02715                     LastFreed -= 1;
    02716                 }
    02717                 WorkingSetList->LastEntry = LastFreed;
    02718             }
    02719
    02720             //
    02721             // Remove pages.
    02722             //
    02723
    02724             Entry = WorkingSetList->FirstDynamic;
    02725
    02726             while (WsInfo->WorkingSetSize > WorkingSetMaximum) {
    02727                 if (Wsle[Entry].u1.e1.Valid != 0) {
    02728                     PointerPte = MiGetPteAddress (
    02729                                             Wsle[Entry].u1.VirtualAddress);
    02730                     PERFINFO_GET_PAGE_INFO(PointerPte);
    02731
    02732                     if (MiFreeWsle(Entry, WsInfo, PointerPte)) {
    02733                         PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_ADJUSTWS,
    02734                                               WsInfo);
    02735                     }
    02736                 }
    02737                 Entry += 1;
    02738                 if (Entry > LastFreed) {
    02739                     FreeTryCount += 1;
    02740                     if (FreeTryCount > MM_RETRY_COUNT) {
    02741
    02742                         //
    02743                         // Page table pages are not becoming free, give up
    02744                         // and return an error.
    02745                         //
    02746
    02747                         ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
    02748
    02749                         break;
    02750                     }
    02751                     Entry = WorkingSetList->FirstDynamic;
    02752                 }
    02753             }
    02754
    02755             if (FreeTryCount <= MM_RETRY_COUNT) {
    02756                 WorkingSetList->Quota = WorkingSetMaximum;
    02757             }
    02758         }
    02759     }
    02760
    02761     //
    02762     // Adjust the number of pages above the working set minimum.
    02763     //
    02764
    02765     PagesAbove = (LONG)WsInfo->WorkingSetSize -
    02766                                (LONG)WsInfo->MinimumWorkingSetSize;
    02767     NewPagesAbove = (LONG)WsInfo->WorkingSetSize -
    02768                                (LONG)WorkingSetMinimum;
    02769
    02770     LOCK_PFN (OldIrql);
    02771     if (PagesAbove > 0) {
    02772         MmPagesAboveWsMinimum -= (ULONG)PagesAbove;
    02773     }
    02774     if (NewPagesAbove > 0) {
    02775         MmPagesAboveWsMinimum += (ULONG)NewPagesAbove;
    02776     }
    02777     UNLOCK_PFN (OldIrql);
    02778
    02779     if (FreeTryCount <= MM_RETRY_COUNT) {
    02780         WsInfo->MaximumWorkingSetSize = WorkingSetMaximum;
    02781         WsInfo->MinimumWorkingSetSize = WorkingSetMinimum;
    02782
    02783         if (WorkingSetMinimum >= WorkingSetList->Quota) {
    02784             WorkingSetList->Quota = WorkingSetMinimum;
    02785         }
    02786     }
    02787     else {
    02788         LOCK_PFN (OldIrql);
    02789
    02790         MmResidentAvailablePages += i;
    02791         MM_BUMP_COUNTER(55, i);
    02792
    02793         UNLOCK_PFN (OldIrql);
    02794     }
    02795
    02796
    02797     ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
    02798             (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
    02799
    02800     if ((WorkingSetList->HashTable == NULL) &&
    02801         (WsInfo->MaximumWorkingSetSize > ((1536*1024) >> PAGE_SHIFT))) {
    02802
    02803         //
    02804         // The working set list consists of more than a single page.
    02805         //
    02806
    02807         MiGrowWsleHash (WsInfo);
    02808     }
    02809
    02810 Returns:
    02811
    02812     if (SystemCache) {
    02813         UNLOCK_SYSTEM_WS (OldIrql2);
    02814     } else {
    02815         UNLOCK_WS (CurrentProcess);
    02816     }
    02817
    02818     MmUnlockPagableImageSection(ExPageLockHandle);
    02819
    02820     return ReturnStatus;
    02821 }

LOGICAL MmAssignProcessToJob | ( | IN PEPROCESS | Process | ) |

Definition at line 2386 of file wslist.c.

References FALSE, KeAttachProcess(), KeDetachProcess(), LOCK_WS_AND_ADDRESS_SPACE, PAGED_CODE, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, PsChangeJobMemoryUsage(), PsGetCurrentProcess, Status, TRUE, and UNLOCK_WS_AND_ADDRESS_SPACE.

Referenced by PspAddProcessToJob().

    02392                    :
    02393
    02394     This routine acquires the working set lock so a consistent snapshot of
    02395     the argument process' commit charges and working set size can be used
    02396     when adding this process to a job.
    02397
    02398 Arguments:
    02399
    02400     Process - Supplies a pointer to the process to operate upon.
    02401
    02402 Return Value:
    02403
    02404     TRUE if the process is allowed to join the job, FALSE otherwise.
    02405
    02406     Note that FALSE cannot be returned without changing the code in ps.
    02407
    02408 Environment:
    02409
    02410     Kernel mode, IRQL APC_LEVEL or below.  The caller provides protection
    02411     from the target process going away.
    02412
    02413 --*/
    02414
    02415 {
    02416     LOGICAL Attached;
    02417     LOGICAL Status;
    02418
    02419     PAGED_CODE ();
    02420
    02421     Attached = FALSE;
    02422
    02423     if (PsGetCurrentProcess() != Process) {
    02424         KeAttachProcess (&Process->Pcb);
    02425         Attached = TRUE;
    02426     }
    02427
    02428     LOCK_WS_AND_ADDRESS_SPACE (Process);
    02429
    02430     Status = PsChangeJobMemoryUsage (Process->CommitCharge);
    02431
    02432     //
    02433     // Join the job unconditionally.  If the process is over any limits, it
    02434     // will be caught on its next request.
    02435     //
    02436
    02437     Process->JobStatus |= PS_JOB_STATUS_REPORT_COMMIT_CHANGES;
    02438
    02439     UNLOCK_WS_AND_ADDRESS_SPACE (Process);
    02440
    02441     if (Attached) {
    02442         KeDetachProcess();
    02443     }
    02444
    02445     return TRUE;
    02446 }

LOGICAL MmEnforceWorkingSetLimit | ( | IN PMMSUPPORT | WsInfo,
|  | IN LOGICAL | Enable
| ) |

Definition at line 543 of file wslist.c.

References LOCK_EXPANSION, LOCK_SYSTEM_WS, LOCK_WS, MmSystemCacheWs, PsGetCurrentProcess, UNLOCK_EXPANSION, UNLOCK_SYSTEM_WS, and UNLOCK_WS.

Referenced by NtSetInformationJobObject(), PspAddProcessToJob(), and PspApplyJobLimitsToProcess().

    00550                    :
    00551
    00552     This function enables hard enforcement of the working set maximum for
    00553     the specified WsInfo.
    00554
    00555 Arguments:
    00556
    00557     WsInfo - Supplies the working set info pointer.
    00558
    00559     Enable - Supplies TRUE if enabling hard enforcement, FALSE if not.
    00560
    00561 Return Value:
    00562
    00563     The previous state of the working set enforcement.
    00564
    00565 Environment:
    00566
    00567     Kernel mode, APCs disabled.  The working set lock must NOT be held.
    00568     The caller guarantees that the target WsInfo cannot go away.
    00569
    00570 --*/
    00571
    00572 {
    00573     KIRQL OldIrql;
    00574
    00575     LOGICAL PreviousWorkingSetEnforcement;
    00576
    00577     LOCK_EXPANSION (OldIrql);
    00578
    00579     PreviousWorkingSetEnforcement = WsInfo->u.Flags.WorkingSetHard;
    00580
    00581     WsInfo->u.Flags.WorkingSetHard = Enable;
    00582
    00583     UNLOCK_EXPANSION (OldIrql);
    00584
    00585 #if 0
    00586
    00587     PEPROCESS CurrentProcess;
    00588
    00589     //
    00590     // Get the working set lock and disable APCs.
    00591     // The working set could be trimmed at this point if it is excessive.
    00592     //
    00593     // The working set lock cannot be acquired at this point without updating
    00594     // ps in order to avoid deadlock.
    00595     //
    00596
    00597     if (WsInfo == &MmSystemCacheWs) {
    00598         LOCK_SYSTEM_WS (OldIrql2);
    00599         UNLOCK_SYSTEM_WS (OldIrql2);
    00600     }
    00601     else if (WsInfo->u.Flags.SessionSpace == 0) {
    00602         CurrentProcess = PsGetCurrentProcess ();
    00603         LOCK_WS (CurrentProcess);
    00604
    00605         UNLOCK_WS (CurrentProcess);
    00606     }
    00607 #endif
    00608
    00609     return PreviousWorkingSetEnforcement;
    00610 }

## Variable Documentation

LOGICAL MiTrimRemovalPagesOnly

| Definition at line 50 of file wslist.c. Referenced by MiEmptyWorkingSet(), and MmRemovePhysicalMemory().

ULONG MmFaultsTakenToGoAboveMaxWs = 100

| Definition at line 33 of file wslist.c.

ULONG MmFaultsTakenToGoAboveMinWs = 16

| Definition at line 34 of file wslist.c. Referenced by MiDoReplacement().

ULONG MmMaximumWorkingSetSize

| Definition at line 31 of file wslist.c. Referenced by MmAdjustWorkingSetSize(), and MmInitSystem().

ULONG MmPagedPoolPage

| Definition at line 38 of file wslist.c.

ULONG MmSystemCachePage

| Definition at line 37 of file wslist.c.

ULONG MmSystemCodePage

| Definition at line 36 of file wslist.c.

ULONG MmSystemDriverPage

| Definition at line 39 of file wslist.c.

ULONG MmTransitionSharedPages

| Definition at line 47 of file wslist.c.

ULONG MmTransitionSharedPagesPeak

| Definition at line 48 of file wslist.c. Referenced by MiLocateAndReserveWsle(), and NtQuerySystemInformation().