mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 21:44:31 +00:00
[NTOS:MM] Make the page LRU list a real LRU list.
Also, implement flushing mapped sections to disk on shutdown.
This commit is contained in:
parent
bde2ee571a
commit
8a8b4db447
57
ntoskrnl/cache/section/newmm.h
vendored
57
ntoskrnl/cache/section/newmm.h
vendored
|
@ -3,22 +3,6 @@
|
||||||
#include <internal/arch/mm.h>
|
#include <internal/arch/mm.h>
|
||||||
|
|
||||||
/* TYPES *********************************************************************/
|
/* TYPES *********************************************************************/
|
||||||
|
|
||||||
#define PFN_FROM_SSE(E) ((PFN_NUMBER)((E) >> PAGE_SHIFT))
|
|
||||||
#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
|
|
||||||
#define MM_IS_WAIT_PTE(E) \
|
|
||||||
(IS_SWAP_FROM_SSE(E) && SWAPENTRY_FROM_SSE(E) == MM_WAIT_ENTRY)
|
|
||||||
#define MAKE_PFN_SSE(P) ((ULONG_PTR)((P) << PAGE_SHIFT))
|
|
||||||
#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
|
|
||||||
#define MAKE_SWAP_SSE(S) (((ULONG_PTR)(S) << 1) | 0x1)
|
|
||||||
#define DIRTY_SSE(E) ((E) | 2)
|
|
||||||
#define CLEAN_SSE(E) ((E) & ~2)
|
|
||||||
#define IS_DIRTY_SSE(E) ((E) & 2)
|
|
||||||
#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
|
|
||||||
#define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFC) >> 2)
|
|
||||||
#define MAX_SHARE_COUNT 0x3FF
|
|
||||||
#define MAKE_SSE(P, C) ((ULONG_PTR)((P) | ((C) << 2)))
|
|
||||||
|
|
||||||
#define MM_SEGMENT_FINALIZE (0x40000000)
|
#define MM_SEGMENT_FINALIZE (0x40000000)
|
||||||
|
|
||||||
#define RMAP_SEGMENT_MASK ~((ULONG_PTR)0xff)
|
#define RMAP_SEGMENT_MASK ~((ULONG_PTR)0xff)
|
||||||
|
@ -123,25 +107,6 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MiInitializeSectionPageTable(PMM_SECTION_SEGMENT Segment);
|
MiInitializeSectionPageTable(PMM_SECTION_SEGMENT Segment);
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
_MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
|
||||||
PLARGE_INTEGER Offset,
|
|
||||||
ULONG_PTR Entry,
|
|
||||||
const char *file,
|
|
||||||
int line);
|
|
||||||
|
|
||||||
ULONG_PTR
|
|
||||||
NTAPI
|
|
||||||
_MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
|
||||||
PLARGE_INTEGER Offset,
|
|
||||||
const char *file,
|
|
||||||
int line);
|
|
||||||
|
|
||||||
#define MmSetPageEntrySectionSegment(S,O,E) _MmSetPageEntrySectionSegment(S,O,E,__FILE__,__LINE__)
|
|
||||||
|
|
||||||
#define MmGetPageEntrySectionSegment(S,O) _MmGetPageEntrySectionSegment(S,O,__FILE__,__LINE__)
|
|
||||||
|
|
||||||
typedef VOID (NTAPI *FREE_SECTION_PAGE_FUN)(
|
typedef VOID (NTAPI *FREE_SECTION_PAGE_FUN)(
|
||||||
PMM_SECTION_SEGMENT Segment,
|
PMM_SECTION_SEGMENT Segment,
|
||||||
PLARGE_INTEGER Offset);
|
PLARGE_INTEGER Offset);
|
||||||
|
@ -151,12 +116,6 @@ NTAPI
|
||||||
MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment,
|
MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment,
|
||||||
FREE_SECTION_PAGE_FUN FreePage);
|
FREE_SECTION_PAGE_FUN FreePage);
|
||||||
|
|
||||||
/* Yields a lock */
|
|
||||||
PMM_SECTION_SEGMENT
|
|
||||||
NTAPI
|
|
||||||
MmGetSectionAssociation(PFN_NUMBER Page,
|
|
||||||
PLARGE_INTEGER Offset);
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MmSetSectionAssociation(PFN_NUMBER Page,
|
MmSetSectionAssociation(PFN_NUMBER Page,
|
||||||
|
@ -267,22 +226,6 @@ MmPageOutDeleteMapping(PVOID Context,
|
||||||
PEPROCESS Process,
|
PEPROCESS Process,
|
||||||
PVOID Address);
|
PVOID Address);
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
_MmLockSectionSegment(PMM_SECTION_SEGMENT Segment,
|
|
||||||
const char *file,
|
|
||||||
int line);
|
|
||||||
|
|
||||||
#define MmLockSectionSegment(x) _MmLockSectionSegment(x,__FILE__,__LINE__)
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
_MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment,
|
|
||||||
const char *file,
|
|
||||||
int line);
|
|
||||||
|
|
||||||
#define MmUnlockSectionSegment(x) _MmUnlockSectionSegment(x,__FILE__,__LINE__)
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
MmFreeCacheSectionPage(PVOID Context,
|
MmFreeCacheSectionPage(PVOID Context,
|
||||||
MEMORY_AREA* MemoryArea,
|
MEMORY_AREA* MemoryArea,
|
||||||
|
|
|
@ -357,6 +357,8 @@ typedef struct _MMPFN
|
||||||
|
|
||||||
// HACK until WS lists are supported
|
// HACK until WS lists are supported
|
||||||
MMWSLE Wsle;
|
MMWSLE Wsle;
|
||||||
|
struct _MMPFN* NextLRU;
|
||||||
|
struct _MMPFN* PreviousLRU;
|
||||||
} MMPFN, *PMMPFN;
|
} MMPFN, *PMMPFN;
|
||||||
|
|
||||||
extern PMMPFN MmPfnDatabase;
|
extern PMMPFN MmPfnDatabase;
|
||||||
|
@ -877,6 +879,11 @@ NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MmPageOutPhysicalAddress(PFN_NUMBER Page);
|
MmPageOutPhysicalAddress(PFN_NUMBER Page);
|
||||||
|
|
||||||
|
PMM_SECTION_SEGMENT
|
||||||
|
NTAPI
|
||||||
|
MmGetSectionAssociation(PFN_NUMBER Page,
|
||||||
|
PLARGE_INTEGER Offset);
|
||||||
|
|
||||||
/* freelist.c **********************************************************/
|
/* freelist.c **********************************************************/
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
|
@ -950,20 +957,12 @@ MiGetPfnEntryIndex(IN PMMPFN Pfn1)
|
||||||
|
|
||||||
PFN_NUMBER
|
PFN_NUMBER
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetLRUNextUserPage(PFN_NUMBER PreviousPage);
|
MmGetLRUNextUserPage(PFN_NUMBER PreviousPage, BOOLEAN MoveToLast);
|
||||||
|
|
||||||
PFN_NUMBER
|
PFN_NUMBER
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetLRUFirstUserPage(VOID);
|
MmGetLRUFirstUserPage(VOID);
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
MmInsertLRULastUserPage(PFN_NUMBER Page);
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
MmRemoveLRUUserPage(PFN_NUMBER Page);
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MmDumpArmPfnDatabase(
|
MmDumpArmPfnDatabase(
|
||||||
|
@ -1232,6 +1231,37 @@ MmFindRegion(
|
||||||
|
|
||||||
/* section.c *****************************************************************/
|
/* section.c *****************************************************************/
|
||||||
|
|
||||||
|
#define PFN_FROM_SSE(E) ((PFN_NUMBER)((E) >> PAGE_SHIFT))
|
||||||
|
#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
|
||||||
|
#define MM_IS_WAIT_PTE(E) \
|
||||||
|
(IS_SWAP_FROM_SSE(E) && SWAPENTRY_FROM_SSE(E) == MM_WAIT_ENTRY)
|
||||||
|
#define MAKE_PFN_SSE(P) ((ULONG_PTR)((P) << PAGE_SHIFT))
|
||||||
|
#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
|
||||||
|
#define MAKE_SWAP_SSE(S) (((ULONG_PTR)(S) << 1) | 0x1)
|
||||||
|
#define DIRTY_SSE(E) ((E) | 2)
|
||||||
|
#define CLEAN_SSE(E) ((E) & ~2)
|
||||||
|
#define IS_DIRTY_SSE(E) ((E) & 2)
|
||||||
|
#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
|
||||||
|
#define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFC) >> 2)
|
||||||
|
#define MAX_SHARE_COUNT 0x3FF
|
||||||
|
#define MAKE_SSE(P, C) ((ULONG_PTR)((P) | ((C) << 2)))
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
_MmLockSectionSegment(PMM_SECTION_SEGMENT Segment,
|
||||||
|
const char *file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
#define MmLockSectionSegment(x) _MmLockSectionSegment(x,__FILE__,__LINE__)
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
_MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment,
|
||||||
|
const char *file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
#define MmUnlockSectionSegment(x) _MmUnlockSectionSegment(x,__FILE__,__LINE__)
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetImageInformation(
|
MmGetImageInformation(
|
||||||
|
@ -1372,6 +1402,27 @@ MmExtendSection(
|
||||||
_In_ PVOID Section,
|
_In_ PVOID Section,
|
||||||
_Inout_ PLARGE_INTEGER NewSize);
|
_Inout_ PLARGE_INTEGER NewSize);
|
||||||
|
|
||||||
|
/* sptab.c *******************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
_MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
||||||
|
PLARGE_INTEGER Offset,
|
||||||
|
ULONG_PTR Entry,
|
||||||
|
const char *file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
ULONG_PTR
|
||||||
|
NTAPI
|
||||||
|
_MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
|
||||||
|
PLARGE_INTEGER Offset,
|
||||||
|
const char *file,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
#define MmSetPageEntrySectionSegment(S,O,E) _MmSetPageEntrySectionSegment(S,O,E,__FILE__,__LINE__)
|
||||||
|
|
||||||
|
#define MmGetPageEntrySectionSegment(S,O) _MmGetPageEntrySectionSegment(S,O,__FILE__,__LINE__)
|
||||||
|
|
||||||
/* sysldr.c ******************************************************************/
|
/* sysldr.c ******************************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
|
|
@ -80,11 +80,7 @@ MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
|
||||||
KeBugCheck(MEMORY_MANAGEMENT);
|
KeBugCheck(MEMORY_MANAGEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MmGetReferenceCountPage(Page) == 1)
|
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||||
{
|
|
||||||
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
|
|
||||||
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
MmDereferencePage(Page);
|
MmDereferencePage(Page);
|
||||||
|
|
||||||
|
@ -142,7 +138,6 @@ NTSTATUS
|
||||||
MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
|
MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
|
||||||
{
|
{
|
||||||
PFN_NUMBER CurrentPage;
|
PFN_NUMBER CurrentPage;
|
||||||
PFN_NUMBER NextPage;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
(*NrFreedPages) = 0;
|
(*NrFreedPages) = 0;
|
||||||
|
@ -158,13 +153,14 @@ MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
|
||||||
(*NrFreedPages)++;
|
(*NrFreedPages)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
NextPage = MmGetLRUNextUserPage(CurrentPage);
|
CurrentPage = MmGetLRUNextUserPage(CurrentPage, TRUE);
|
||||||
if (NextPage <= CurrentPage)
|
}
|
||||||
{
|
|
||||||
/* We wrapped around, so we're done */
|
if (CurrentPage)
|
||||||
break;
|
{
|
||||||
}
|
KIRQL OldIrql = MiAcquirePfnLock();
|
||||||
CurrentPage = NextPage;
|
MmDereferencePage(CurrentPage);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -209,14 +205,13 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
|
||||||
/*
|
/*
|
||||||
* Allocate always memory for the non paged pool and for the pager thread.
|
* Allocate always memory for the non paged pool and for the pager thread.
|
||||||
*/
|
*/
|
||||||
if ((Consumer == MC_SYSTEM) /* || MiIsBalancerThread() */)
|
if (Consumer == MC_SYSTEM)
|
||||||
{
|
{
|
||||||
Page = MmAllocPage(Consumer);
|
Page = MmAllocPage(Consumer);
|
||||||
if (Page == 0)
|
if (Page == 0)
|
||||||
{
|
{
|
||||||
KeBugCheck(NO_PAGES_AVAILABLE);
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
||||||
}
|
}
|
||||||
if (Consumer == MC_USER) MmInsertLRULastUserPage(Page);
|
|
||||||
*AllocatedPage = Page;
|
*AllocatedPage = Page;
|
||||||
if (MmAvailablePages < MiMinimumAvailablePages)
|
if (MmAvailablePages < MiMinimumAvailablePages)
|
||||||
MmRebalanceMemoryConsumers();
|
MmRebalanceMemoryConsumers();
|
||||||
|
@ -257,7 +252,6 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
|
||||||
KeBugCheck(NO_PAGES_AVAILABLE);
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
|
|
||||||
*AllocatedPage = Page;
|
*AllocatedPage = Page;
|
||||||
|
|
||||||
if (MmAvailablePages < MiMinimumAvailablePages)
|
if (MmAvailablePages < MiMinimumAvailablePages)
|
||||||
|
@ -276,7 +270,6 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
|
||||||
{
|
{
|
||||||
KeBugCheck(NO_PAGES_AVAILABLE);
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
||||||
}
|
}
|
||||||
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
|
|
||||||
*AllocatedPage = Page;
|
*AllocatedPage = Page;
|
||||||
|
|
||||||
if (MmAvailablePages < MiMinimumAvailablePages)
|
if (MmAvailablePages < MiMinimumAvailablePages)
|
||||||
|
|
|
@ -35,95 +35,127 @@ SIZE_T MmPagedPoolCommit;
|
||||||
SIZE_T MmPeakCommitment;
|
SIZE_T MmPeakCommitment;
|
||||||
SIZE_T MmtotalCommitLimitMaximum;
|
SIZE_T MmtotalCommitLimitMaximum;
|
||||||
|
|
||||||
static RTL_BITMAP MiUserPfnBitMap;
|
PMMPFN FirstUserLRUPfn;
|
||||||
|
PMMPFN LastUserLRUPfn;
|
||||||
|
|
||||||
/* FUNCTIONS *************************************************************/
|
/* FUNCTIONS *************************************************************/
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
MiInitializeUserPfnBitmap(VOID)
|
|
||||||
{
|
|
||||||
PVOID Bitmap;
|
|
||||||
|
|
||||||
/* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
|
|
||||||
Bitmap = ExAllocatePoolWithTag(NonPagedPool,
|
|
||||||
(((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
|
|
||||||
TAG_MM);
|
|
||||||
ASSERT(Bitmap);
|
|
||||||
|
|
||||||
/* Initialize it and clear all the bits to begin with */
|
|
||||||
RtlInitializeBitMap(&MiUserPfnBitMap,
|
|
||||||
Bitmap,
|
|
||||||
(ULONG)MmHighestPhysicalPage + 1);
|
|
||||||
RtlClearAllBits(&MiUserPfnBitMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
PFN_NUMBER
|
PFN_NUMBER
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetLRUFirstUserPage(VOID)
|
MmGetLRUFirstUserPage(VOID)
|
||||||
{
|
{
|
||||||
ULONG Position;
|
PFN_NUMBER Page;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
|
||||||
/* Find the first user page */
|
/* Find the first user page */
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
|
|
||||||
MiReleasePfnLock(OldIrql);
|
|
||||||
if (Position == 0xFFFFFFFF) return 0;
|
|
||||||
|
|
||||||
/* Return it */
|
if (FirstUserLRUPfn == NULL)
|
||||||
ASSERT(Position != 0);
|
{
|
||||||
ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
|
MiReleasePfnLock(OldIrql);
|
||||||
return Position;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Page = MiGetPfnEntryIndex(FirstUserLRUPfn);
|
||||||
|
MmReferencePage(Page);
|
||||||
|
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
|
||||||
|
return Page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
MmInsertLRULastUserPage(PFN_NUMBER Page)
|
||||||
MmInsertLRULastUserPage(PFN_NUMBER Pfn)
|
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
MI_ASSERT_PFN_LOCK_HELD();
|
||||||
|
|
||||||
/* Set the page as a user page */
|
PMMPFN Pfn = MiGetPfnEntry(Page);
|
||||||
ASSERT(Pfn != 0);
|
|
||||||
ASSERT_IS_ROS_PFN(MiGetPfnEntry(Pfn));
|
if (FirstUserLRUPfn == NULL)
|
||||||
ASSERT(!RtlCheckBit(&MiUserPfnBitMap, (ULONG)Pfn));
|
FirstUserLRUPfn = Pfn;
|
||||||
OldIrql = MiAcquirePfnLock();
|
|
||||||
RtlSetBit(&MiUserPfnBitMap, (ULONG)Pfn);
|
Pfn->PreviousLRU = LastUserLRUPfn;
|
||||||
MiReleasePfnLock(OldIrql);
|
|
||||||
|
if (LastUserLRUPfn != NULL)
|
||||||
|
LastUserLRUPfn->NextLRU = Pfn;
|
||||||
|
LastUserLRUPfn = Pfn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
MmRemoveLRUUserPage(PFN_NUMBER Page)
|
||||||
|
{
|
||||||
|
MI_ASSERT_PFN_LOCK_HELD();
|
||||||
|
|
||||||
|
/* Unset the page as a user page */
|
||||||
|
ASSERT(Page != 0);
|
||||||
|
|
||||||
|
PMMPFN Pfn = MiGetPfnEntry(Page);
|
||||||
|
|
||||||
|
ASSERT_IS_ROS_PFN(Pfn);
|
||||||
|
|
||||||
|
if (Pfn->PreviousLRU)
|
||||||
|
{
|
||||||
|
ASSERT(Pfn->PreviousLRU->NextLRU == Pfn);
|
||||||
|
Pfn->PreviousLRU->NextLRU = Pfn->NextLRU;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(FirstUserLRUPfn == Pfn);
|
||||||
|
FirstUserLRUPfn = Pfn->NextLRU;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pfn->NextLRU)
|
||||||
|
{
|
||||||
|
ASSERT(Pfn->NextLRU->PreviousLRU == Pfn);
|
||||||
|
Pfn->NextLRU->PreviousLRU = Pfn->PreviousLRU;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(Pfn == LastUserLRUPfn);
|
||||||
|
LastUserLRUPfn = Pfn->PreviousLRU;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pfn->PreviousLRU = Pfn->NextLRU = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFN_NUMBER
|
PFN_NUMBER
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetLRUNextUserPage(PFN_NUMBER PreviousPfn)
|
MmGetLRUNextUserPage(PFN_NUMBER PreviousPage, BOOLEAN MoveToLast)
|
||||||
{
|
{
|
||||||
ULONG Position;
|
PFN_NUMBER Page = 0;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
|
||||||
/* Find the next user page */
|
/* Find the next user page */
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
Position = RtlFindSetBits(&MiUserPfnBitMap, 1, (ULONG)PreviousPfn + 1);
|
|
||||||
|
PMMPFN PreviousPfn = MiGetPfnEntry(PreviousPage);
|
||||||
|
PMMPFN NextPfn = PreviousPfn->NextLRU;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move this one at the end of the list.
|
||||||
|
* It may be freed by MmDereferencePage below.
|
||||||
|
* If it's not, then it means it is still hanging in some process address space.
|
||||||
|
* This avoids paging-out e.g. ntdll early just because it's mapped first time.
|
||||||
|
*/
|
||||||
|
if (MoveToLast)
|
||||||
|
{
|
||||||
|
MmRemoveLRUUserPage(PreviousPage);
|
||||||
|
MmInsertLRULastUserPage(PreviousPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NextPfn)
|
||||||
|
{
|
||||||
|
Page = MiGetPfnEntryIndex(NextPfn);
|
||||||
|
MmReferencePage(Page);
|
||||||
|
}
|
||||||
|
|
||||||
|
MmDereferencePage(PreviousPage);
|
||||||
|
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
if (Position == 0xFFFFFFFF) return 0;
|
|
||||||
|
|
||||||
/* Return it */
|
return Page;
|
||||||
ASSERT(Position != 0);
|
|
||||||
ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
|
|
||||||
return Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
MmRemoveLRUUserPage(PFN_NUMBER Page)
|
|
||||||
{
|
|
||||||
KIRQL OldIrql;
|
|
||||||
|
|
||||||
/* Unset the page as a user page */
|
|
||||||
ASSERT(Page != 0);
|
|
||||||
ASSERT_IS_ROS_PFN(MiGetPfnEntry(Page));
|
|
||||||
ASSERT(RtlCheckBit(&MiUserPfnBitMap, (ULONG)Page));
|
|
||||||
OldIrql = MiAcquirePfnLock();
|
|
||||||
RtlClearBit(&MiUserPfnBitMap, (ULONG)Page);
|
|
||||||
MiReleasePfnLock(OldIrql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -548,6 +580,13 @@ MmDereferencePage(PFN_NUMBER Pfn)
|
||||||
Pfn1->u3.e2.ReferenceCount--;
|
Pfn1->u3.e2.ReferenceCount--;
|
||||||
if (Pfn1->u3.e2.ReferenceCount == 0)
|
if (Pfn1->u3.e2.ReferenceCount == 0)
|
||||||
{
|
{
|
||||||
|
/* Apply LRU hack */
|
||||||
|
if (Pfn1->u4.MustBeCached)
|
||||||
|
{
|
||||||
|
MmRemoveLRUUserPage(Pfn);
|
||||||
|
Pfn1->u4.MustBeCached = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark the page temporarily as valid, we're going to make it free soon */
|
/* Mark the page temporarily as valid, we're going to make it free soon */
|
||||||
Pfn1->u3.e1.PageLocation = ActiveAndValid;
|
Pfn1->u3.e1.PageLocation = ActiveAndValid;
|
||||||
|
|
||||||
|
@ -590,6 +629,15 @@ MmAllocPage(ULONG Type)
|
||||||
Pfn1->u1.SwapEntry = 0;
|
Pfn1->u1.SwapEntry = 0;
|
||||||
Pfn1->RmapListHead = NULL;
|
Pfn1->RmapListHead = NULL;
|
||||||
|
|
||||||
|
Pfn1->NextLRU = NULL;
|
||||||
|
Pfn1->PreviousLRU = NULL;
|
||||||
|
|
||||||
|
if (Type == MC_USER)
|
||||||
|
{
|
||||||
|
Pfn1->u4.MustBeCached = 1; /* HACK again */
|
||||||
|
MmInsertLRULastUserPage(PfnOffset);
|
||||||
|
}
|
||||||
|
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
return PfnOffset;
|
return PfnOffset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
VOID NTAPI MiInitializeUserPfnBitmap(VOID);
|
|
||||||
|
|
||||||
BOOLEAN Mm64BitPhysicalAddress = FALSE;
|
BOOLEAN Mm64BitPhysicalAddress = FALSE;
|
||||||
ULONG MmReadClusterSize;
|
ULONG MmReadClusterSize;
|
||||||
//
|
//
|
||||||
|
@ -235,7 +233,6 @@ MmInitSystem(IN ULONG Phase,
|
||||||
MiDbgDumpAddressSpace();
|
MiDbgDumpAddressSpace();
|
||||||
|
|
||||||
MmInitGlobalKernelPageDirectory();
|
MmInitGlobalKernelPageDirectory();
|
||||||
MiInitializeUserPfnBitmap();
|
|
||||||
MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
|
MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
|
||||||
MmInitializeRmapList();
|
MmInitializeRmapList();
|
||||||
MmInitSectionImplementation();
|
MmInitSectionImplementation();
|
||||||
|
|
|
@ -21,6 +21,44 @@ VOID
|
||||||
MiShutdownSystem(VOID)
|
MiShutdownSystem(VOID)
|
||||||
{
|
{
|
||||||
ULONG i;
|
ULONG i;
|
||||||
|
PFN_NUMBER Page;
|
||||||
|
BOOLEAN Dirty;
|
||||||
|
|
||||||
|
/* Loop through all the pages owned by the legacy Mm and page them out, if needed. */
|
||||||
|
/* We do it twice, since flushing can cause the FS to dirtify new pages */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Dirty = FALSE;
|
||||||
|
|
||||||
|
Page = MmGetLRUFirstUserPage();
|
||||||
|
while (Page)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER SegmentOffset;
|
||||||
|
PMM_SECTION_SEGMENT Segment = MmGetSectionAssociation(Page, &SegmentOffset);
|
||||||
|
|
||||||
|
if (Segment)
|
||||||
|
{
|
||||||
|
if ((*Segment->Flags) & MM_DATAFILE_SEGMENT)
|
||||||
|
{
|
||||||
|
MmLockSectionSegment(Segment);
|
||||||
|
|
||||||
|
ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
|
||||||
|
|
||||||
|
if (!IS_SWAP_FROM_SSE(Entry) && IS_DIRTY_SSE(Entry))
|
||||||
|
{
|
||||||
|
Dirty = TRUE;
|
||||||
|
MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
MmUnlockSectionSegment(Segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
MmDereferenceSegment(Segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
Page = MmGetLRUNextUserPage(Page, FALSE);
|
||||||
|
}
|
||||||
|
} while (Dirty);
|
||||||
|
|
||||||
/* Loop through all the paging files */
|
/* Loop through all the paging files */
|
||||||
for (i = 0; i < MmNumberOfPagingFiles; i++)
|
for (i = 0; i < MmNumberOfPagingFiles; i++)
|
||||||
|
|
Loading…
Reference in a new issue