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().


Generated on Sat May 15 19:46:10 2004 for test by doxygen 1.3.7