Author: jgardou Date: Thu Jan 28 21:17:28 2016 New Revision: 70649
URL: http://svn.reactos.org/svn/reactos?rev=70649&view=rev Log: [BRANCHES/TRANSITIONPTE] - Make the thing build
Modified: branches/TransitionPte/ntoskrnl/mm/balance.c branches/TransitionPte/ntoskrnl/mm/pagefile.c
Modified: branches/TransitionPte/ntoskrnl/mm/balance.c URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/balanc... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/balance.c [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/balance.c [iso-8859-1] Thu Jan 28 21:17:28 2016 @@ -24,14 +24,7 @@
#define TEST_PAGING
-/* TYPES ********************************************************************/ -typedef struct _MM_ALLOCATION_REQUEST -{ - PFN_NUMBER Page; - LIST_ENTRY ListEntry; - KEVENT Event; -} -MM_ALLOCATION_REQUEST, *PMM_ALLOCATION_REQUEST; + /* GLOBALS ******************************************************************/
MM_MEMORY_CONSUMER MiMemoryConsumers[MC_MAXIMUM]; @@ -51,15 +44,13 @@ NTAPI MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages) { - memset(MiMemoryConsumers, 0, sizeof(MiMemoryConsumers)); - InitializeListHead(&AllocationListHead); - KeInitializeSpinLock(&AllocationListLock); - - MiNrTotalPages = NrAvailablePages; - - /* Set up targets. */ - MiMinimumAvailablePages = 128; - MiMinimumPagesPerRun = 256; + memset(MiMemoryConsumers, 0, sizeof(MiMemoryConsumers)); + + MiNrTotalPages = NrAvailablePages; + + /* Set up targets. */ + MiMinimumAvailablePages = 128; + MiMinimumPagesPerRun = 256; if ((NrAvailablePages + NrSystemPages) >= 8192) { MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 4 * 3; @@ -72,54 +63,42 @@ { MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 8; } - MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages - MiMinimumAvailablePages; + MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages - MiMinimumAvailablePages; }
VOID INIT_FUNCTION NTAPI -MmInitializeMemoryConsumer( - ULONG Consumer, - NTSTATUS (*Trim)(ULONG Target, ULONG Priority, PULONG NrFreed)) -{ - MiMemoryConsumers[Consumer].Trim = Trim; +MmInitializeMemoryConsumer(ULONG Consumer, + NTSTATUS (*Trim)(ULONG Target, ULONG Priority, + PULONG NrFreed)) +{ + MiMemoryConsumers[Consumer].Trim = Trim; }
NTSTATUS NTAPI MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page) { - PMM_ALLOCATION_REQUEST Request; - PLIST_ENTRY Entry; - - if (Page == 0) - { - DPRINT1("Tried to release page zero.\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - - if (MmGetReferenceCountPage(Page) == 1) - { - if(Consumer == MC_USER) MmRemoveLRUUserPage(Page); - (void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed); - if ((Entry = ExInterlockedRemoveHeadList(&AllocationListHead, &AllocationListLock)) == NULL) - { - MmDereferencePage(Page); - } - else - { - Request = CONTAINING_RECORD(Entry, MM_ALLOCATION_REQUEST, ListEntry); - MiZeroPhysicalPage(Page); - Request->Page = Page; - KeSetEvent(&Request->Event, IO_NO_INCREMENT, FALSE); - } - } - else - { - MmDereferencePage(Page); - } - - return(STATUS_SUCCESS); + KIRQL OldIrql; + + if (Page == 0) + { + DPRINT1("Tried to release page zero.\n"); + KeBugCheck(MEMORY_MANAGEMENT); + } + + if (MmGetReferenceCountPage(Page) == 1) + { + if(Consumer == MC_USER) MmRemoveLRUUserPage(Page); + (void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed); + } + + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + MmDereferencePage(Page); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + return(STATUS_SUCCESS); }
ULONG @@ -214,8 +193,8 @@ static BOOLEAN MiIsBalancerThread(VOID) { - return (MiBalancerThreadHandle != NULL) && - (PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread); + return (MiBalancerThreadHandle != NULL) && + (PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread); }
VOID @@ -234,97 +213,52 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait, PPFN_NUMBER AllocatedPage) { - ULONG PagesUsed; - PFN_NUMBER Page; - - /* - * Make sure we don't exceed our individual target. - */ - PagesUsed = InterlockedIncrementUL(&MiMemoryConsumers[Consumer].PagesUsed); - if (PagesUsed > MiMemoryConsumers[Consumer].PagesTarget && - !MiIsBalancerThread()) - { - MmRebalanceMemoryConsumers(); - } - - /* - * Allocate always memory for the non paged pool and for the pager thread. - */ - if ((Consumer == MC_SYSTEM) || MiIsBalancerThread()) - { - Page = MmAllocPage(Consumer); - if (Page == 0) - { - KeBugCheck(NO_PAGES_AVAILABLE); - } - if (Consumer == MC_USER) MmInsertLRULastUserPage(Page); - *AllocatedPage = Page; - if (MmAvailablePages < MiMinimumAvailablePages) - MmRebalanceMemoryConsumers(); - return(STATUS_SUCCESS); - } - - /* - * Make sure we don't exceed global targets. - */ - if (MmAvailablePages < MiMinimumAvailablePages) - { - MM_ALLOCATION_REQUEST Request; - - if (!CanWait) - { - (void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed); - MmRebalanceMemoryConsumers(); - return(STATUS_NO_MEMORY); - } - - /* Insert an allocation request. */ - Request.Page = 0; - KeInitializeEvent(&Request.Event, NotificationEvent, FALSE); - - ExInterlockedInsertTailList(&AllocationListHead, &Request.ListEntry, &AllocationListLock); - MmRebalanceMemoryConsumers(); - - KeWaitForSingleObject(&Request.Event, - 0, - KernelMode, - FALSE, - NULL); - - Page = Request.Page; - if (Page == 0) - { - KeBugCheck(NO_PAGES_AVAILABLE); - } - - if(Consumer == MC_USER) MmInsertLRULastUserPage(Page); - *AllocatedPage = Page; - - if (MmAvailablePages < MiMinimumAvailablePages) - { - MmRebalanceMemoryConsumers(); - } - - return(STATUS_SUCCESS); - } - - /* - * Actually allocate the page. - */ - Page = MmAllocPage(Consumer); - if (Page == 0) - { - KeBugCheck(NO_PAGES_AVAILABLE); - } - if(Consumer == MC_USER) MmInsertLRULastUserPage(Page); - *AllocatedPage = Page; - - if (MmAvailablePages < MiMinimumAvailablePages) - { - MmRebalanceMemoryConsumers(); - } - - return(STATUS_SUCCESS); + ULONG PagesUsed; + PFN_NUMBER Page; + KIRQL OldIrql; + + /* + * Make sure we don't exceed our individual target. + */ + PagesUsed = InterlockedIncrementUL(&MiMemoryConsumers[Consumer].PagesUsed); + if ((PagesUsed > MiMemoryConsumers[Consumer].PagesTarget) && + !MiIsBalancerThread() && + (MmNumberOfPagingFiles == 0)) + { + MmRebalanceMemoryConsumers(); + } + + /* + * Allocate always memory for the non paged pool and for the pager thread. + */ + if ((Consumer == MC_SYSTEM) || MiIsBalancerThread()) + { + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + Page = MmAllocPage(Consumer); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + if (Page == 0) + { + KeBugCheck(NO_PAGES_AVAILABLE); + } + if (Consumer == MC_USER) MmInsertLRULastUserPage(Page); + *AllocatedPage = Page; + return(STATUS_SUCCESS); + } + + /* + * Actually allocate the page. + */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + Page = MmAllocPage(Consumer); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + if (Page == 0) + { + KeBugCheck(NO_PAGES_AVAILABLE); + } + if(Consumer == MC_USER) MmInsertLRULastUserPage(Page); + *AllocatedPage = Page; + + return(STATUS_SUCCESS); }
/* Old implementation of the balancer thread */ @@ -388,50 +322,146 @@ PVOID WaitObjects[2]; NTSTATUS Status; ULONG i; - - WaitObjects[0] = &MiBalancerEvent; - WaitObjects[1] = &MiBalancerTimer; + PVOID LastPagedPoolAddress = MmPagedPoolStart; +#ifdef TEST_PAGING + PULONG PagingTestBuffer; + BOOLEAN TestPage = FALSE; +#endif + + WaitObjects[0] = &MiBalancerTimer; + WaitObjects[1] = &MiBalancerEvent; + +#ifdef TEST_PAGING + PagingTestBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 'tseT'); + DPRINT1("PagingTestBuffer: %p, PTE %p\n", PagingTestBuffer, MiAddressToPte(PagingTestBuffer)); + for (i = 0; i < (PAGE_SIZE / sizeof(ULONG)); i++) + PagingTestBuffer[i] = i; +#endif
while (1) { - Status = KeWaitForMultipleObjects(2, - WaitObjects, - WaitAny, - Executive, - KernelMode, - FALSE, - NULL, - NULL); - - if (Status == STATUS_WAIT_0 || Status == STATUS_WAIT_1) - { - ULONG InitialTarget = 0; - -#if (_MI_PAGING_LEVELS == 2) - if (!MiIsBalancerThread()) - { - /* Clean up the unused PDEs */ - ULONG_PTR Address; - PEPROCESS Process = PsGetCurrentProcess(); - - /* Acquire PFN lock */ - KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - PMMPDE pointerPde; - for (Address = (ULONG_PTR)MI_LOWEST_VAD_ADDRESS; - Address < (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS; - Address += (PAGE_SIZE * PTE_COUNT)) + /* For now, we only age the paged pool, with 100 pages per run. */ + LONG Count = 100; + PVOID Address = LastPagedPoolAddress; + KIRQL OldIrql; + PMMPTE PointerPte; + PMMPDE PointerPde; + ULONG PdeIndex; + MMPTE TempPte; + PMMPFN Pfn1; + BOOLEAN Flush; + + Status = KeWaitForMultipleObjects( + 2, + WaitObjects, + WaitAny, + Executive, + KernelMode, + FALSE, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status); + KeBugCheck(MEMORY_MANAGEMENT); + } + + DPRINT("MM Balancer: Starting to loop.\n"); + + while (Count-- > 0) + { + Address = (PVOID)((ULONG_PTR) Address + PAGE_SIZE); + + /* Acquire PFN lock while we are cooking */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + if (Address > MmPagedPoolEnd) + { + Address = MmPagedPoolStart; + } + + PointerPde = MiAddressToPde(Address); + PointerPte = MiAddressToPte(Address); + + PdeIndex = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE); + + if (MmSystemPagePtes[PdeIndex].u.Hard.Valid == 0) + TempPte.u.Long = 0; + else + TempPte = *PointerPte; + + if (TempPte.u.Hard.Valid == 0) + { + /* Bad luck, not a paged-in address */ +#ifdef TEST_PAGING + if (PointerPte == MiAddressToPte(PagingTestBuffer)) { - if (MiQueryPageTableReferences((PVOID)Address) == 0) + /* Of course it should not magically become a prototype pte */ + ASSERT(TempPte.u.Soft.Prototype == 0); + if (TempPte.u.Soft.Transition == 0) { - pointerPde = MiAddressToPde(Address); - if (pointerPde->u.Hard.Valid) - MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL); - ASSERT(pointerPde->u.Hard.Valid == 0); + /* It was paged out! */ + ASSERT(TempPte.u.Soft.PageFileHigh != 0); + TestPage = TRUE; } } - /* Release lock */ +#endif KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); - } + continue; + } + + Flush = FALSE; + + /* Get the Pfn */ + Pfn1 = MI_PFN_ELEMENT(PFN_FROM_PTE(&TempPte)); + ASSERT(Pfn1->PteAddress == PointerPte); + ASSERT(Pfn1->u3.e1.PrototypePte == 0); + + /* First check if it was written to */ + if (TempPte.u.Hard.Dirty) + Pfn1->u3.e1.Modified = 1; + + /* See if it was accessed since the last time we looked */ + if (TempPte.u.Hard.Accessed) + { + /* Yes! Mark the page as young and fresh again */ + Pfn1->Wsle.u1.e1.Age = 0; + /* Tell the CPU we want to know for the next time */ + TempPte.u.Hard.Accessed = 0; + MI_UPDATE_VALID_PTE(PointerPte, TempPte); + Flush = TRUE; + } + else if (Pfn1->Wsle.u1.e1.Age == 3) + { + /* Page is getting old: Mark the PTE as transition */ + DPRINT1("MM Balancer: putting %p (page %x) as transition.\n", PointerPte, + PFN_FROM_PTE(&TempPte)); + TempPte.u.Hard.Valid = 0; + TempPte.u.Soft.Transition = 1; + TempPte.u.Trans.Protection = MM_READWRITE; + MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&TempPte)); + MI_WRITE_INVALID_PTE(PointerPte, TempPte); + Flush = TRUE; + } + else + { + /* The page is just getting older */ + Pfn1->Wsle.u1.e1.Age++; + } + + /* Flush the TLB entry if we have to */ + if (Flush) + { +#ifdef CONFIG_SMP + // FIXME: Should invalidate entry in every CPU TLB + ASSERT(FALSE); +#endif + KeInvalidateTlbEntry(Address); + } + + /* Unlock, we're done for this address */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + }
DPRINT("MM Balancer: End of the loop.\n");
@@ -452,30 +482,20 @@ TestPage = FALSE; } #endif - do - { - ULONG OldTarget = InitialTarget; - - /* Trim each consumer */ - for (i = 0; i < MC_MAXIMUM; i++) - { - InitialTarget = MiTrimMemoryConsumer(i, InitialTarget); - } - - /* No pages left to swap! */ - if (InitialTarget != 0 && - InitialTarget == OldTarget) - { - /* Game over */ - KeBugCheck(NO_PAGES_AVAILABLE); - } - } - while (InitialTarget != 0); - } - else - { - DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status); - KeBugCheck(MEMORY_MANAGEMENT); + /* Remember this for the next run */ + LastPagedPoolAddress = Address; + + if (Status == STATUS_WAIT_1) + { + /* Balancer thread was woken up by legacy MM + * This means we are really starving. Let's see if this still a problem */ + if ((MmAvailablePages >= MmMinimumFreePages) && (MmNumberOfPagingFiles != 0)) + { + /* Yay! No need to trust the old balancer */ + continue; + } + + MiRosBalancerThread(); } } } @@ -485,44 +505,44 @@ NTAPI MiInitBalancerThread(VOID) { - KPRIORITY Priority; - NTSTATUS Status; + KPRIORITY Priority; + NTSTATUS Status; #if !defined(__GNUC__)
- LARGE_INTEGER dummyJunkNeeded; - dummyJunkNeeded.QuadPart = -20000000; /* 2 sec */ - ; -#endif - - - KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE); - KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer); - KeSetTimerEx(&MiBalancerTimer, + LARGE_INTEGER dummyJunkNeeded; + dummyJunkNeeded.QuadPart = -20000000; /* 2 sec */ + ; +#endif + + + KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE); + KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer); + KeSetTimerEx(&MiBalancerTimer, #if defined(__GNUC__) - (LARGE_INTEGER)(LONGLONG)-20000000LL, /* 2 sec */ + (LARGE_INTEGER)(LONGLONG)-20000000LL, /* 2 sec */ #else - dummyJunkNeeded, -#endif - 2000, /* 2 sec */ - NULL); - - Status = PsCreateSystemThread(&MiBalancerThreadHandle, - THREAD_ALL_ACCESS, - NULL, - NULL, - &MiBalancerThreadId, - MiBalancerThread, - NULL); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(MEMORY_MANAGEMENT); - } - - Priority = LOW_REALTIME_PRIORITY + 1; - NtSetInformationThread(MiBalancerThreadHandle, - ThreadPriority, - &Priority, - sizeof(Priority)); + dummyJunkNeeded, +#endif + 2000, /* 2 sec */ + NULL); + + Status = PsCreateSystemThread(&MiBalancerThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + &MiBalancerThreadId, + MiBalancerThread, + NULL); + if (!NT_SUCCESS(Status)) + { + KeBugCheck(MEMORY_MANAGEMENT); + } + + Priority = LOW_REALTIME_PRIORITY + 1; + NtSetInformationThread(MiBalancerThreadHandle, + ThreadPriority, + &Priority, + sizeof(Priority));
}
Modified: branches/TransitionPte/ntoskrnl/mm/pagefile.c URL: http://svn.reactos.org/svn/reactos/branches/TransitionPte/ntoskrnl/mm/pagefi... ============================================================================== --- branches/TransitionPte/ntoskrnl/mm/pagefile.c [iso-8859-1] (original) +++ branches/TransitionPte/ntoskrnl/mm/pagefile.c [iso-8859-1] Thu Jan 28 21:17:28 2016 @@ -44,23 +44,24 @@
typedef struct _PAGINGFILE { - LIST_ENTRY PagingFileListEntry; - PFILE_OBJECT FileObject; - LARGE_INTEGER MaximumSize; - LARGE_INTEGER CurrentSize; - PFN_NUMBER FreePages; - PFN_NUMBER UsedPages; - PULONG AllocMap; - KSPIN_LOCK AllocMapLock; - ULONG AllocMapSize; - PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; + LIST_ENTRY PagingFileListEntry; + PFILE_OBJECT FileObject; + ULONG_PTR MaximumSize; + ULONG_PTR CurrentSize; + PFN_NUMBER FreePages; + PFN_NUMBER UsedPages; + PVOID AllocMap; + RTL_BITMAP AllocBitMap; + ULONG_PTR AllocBitMapHint; + KSPIN_LOCK AllocMapLock; + PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; } PAGINGFILE, *PPAGINGFILE;
typedef struct _RETRIEVEL_DESCRIPTOR_LIST { - struct _RETRIEVEL_DESCRIPTOR_LIST* Next; - RETRIEVAL_POINTERS_BUFFER RetrievalPointers; + struct _RETRIEVEL_DESCRIPTOR_LIST* Next; + RETRIEVAL_POINTERS_BUFFER RetrievalPointers; } RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
@@ -150,67 +151,67 @@ NTAPI MmShowOutOfSpaceMessagePagingFile(VOID) { - if (!MmSwapSpaceMessage) - { - DPRINT1("MM: Out of swap space.\n"); - MmSwapSpaceMessage = TRUE; - } + if (!MmSwapSpaceMessage) + { + DPRINT1("MM: Out of swap space.\n"); + MmSwapSpaceMessage = TRUE; + } }
static LARGE_INTEGER MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset) { - /* Simple binary search */ - ULONG first, last, mid; - first = 0; - last = RetrievalPointers->ExtentCount - 1; - while (first <= last) - { - mid = (last - first) / 2 + first; - if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart) - { - if (mid == 0) + /* Simple binary search */ + ULONG first, last, mid; + first = 0; + last = RetrievalPointers->ExtentCount - 1; + while (first <= last) + { + mid = (last - first) / 2 + first; + if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart) + { + if (mid == 0) + { + Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart; + return Offset; + } + else + { + if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart) { - Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart; - return Offset; + Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart; + return Offset; } - else - { - if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart) - { - Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart; - return Offset; - } - last = mid - 1; - } - } - else - { - if (mid == RetrievalPointers->ExtentCount - 1) - { - break; - } - if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart) - { - Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart; - return Offset; - } - first = mid + 1; - } - } - KeBugCheck(MEMORY_MANAGEMENT); + last = mid - 1; + } + } + else + { + if (mid == RetrievalPointers->ExtentCount - 1) + { + break; + } + if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart) + { + Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart; + return Offset; + } + first = mid + 1; + } + } + KeBugCheck(MEMORY_MANAGEMENT); #if defined(__GNUC__)
- return (LARGE_INTEGER)0LL; + return (LARGE_INTEGER)0LL; #else
- { - const LARGE_INTEGER dummy = - { + { + const LARGE_INTEGER dummy = + { 0 - }; - return dummy; - } + }; + return dummy; + } #endif }
@@ -218,57 +219,12 @@ NTAPI MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) { - ULONG i; - ULONG_PTR offset; - LARGE_INTEGER file_offset; - IO_STATUS_BLOCK Iosb; - NTSTATUS Status; - KEVENT Event; - UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; - PMDL Mdl = (PMDL)MdlBase; - - DPRINT("MmWriteToSwapPage\n"); - - if (SwapEntry == 0) - { - KeBugCheck(MEMORY_MANAGEMENT); - return(STATUS_UNSUCCESSFUL); - } - - i = FILE_FROM_ENTRY(SwapEntry); - offset = OFFSET_FROM_ENTRY(SwapEntry); - - if (PagingFileList[i]->FileObject == NULL || - PagingFileList[i]->FileObject->DeviceObject == NULL) - { - DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); - KeBugCheck(MEMORY_MANAGEMENT); - } - - MmInitializeMdl(Mdl, NULL, PAGE_SIZE); - MmBuildMdlFromPages(Mdl, &Page); - Mdl->MdlFlags |= MDL_PAGES_LOCKED; - - file_offset.QuadPart = offset * PAGE_SIZE; - file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset); - - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject, - Mdl, - &file_offset, - &Event, - &Iosb); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Iosb.Status; - } - - if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) - { - MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); - } - return(Status); + MMPTE TempPte; + + TempPte.u.Long = 0; + TempPte.u.Soft.PageFileHigh = OFFSET_FROM_ENTRY(SwapEntry); + TempPte.u.Soft.PageFileLow = FILE_FROM_ENTRY(SwapEntry); + return MiWritePageFile(Page, &TempPte); }
@@ -276,65 +232,75 @@ NTAPI MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) { - return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry)); + MMPTE TempPte; + + TempPte.u.Long = 0; + TempPte.u.Soft.PageFileHigh = OFFSET_FROM_ENTRY(SwapEntry); + TempPte.u.Soft.PageFileLow = FILE_FROM_ENTRY(SwapEntry); + return MiReadPageFile(Page, &TempPte); }
NTSTATUS NTAPI MiReadPageFile( - _In_ PFN_NUMBER Page, - _In_ ULONG PageFileIndex, - _In_ ULONG_PTR PageFileOffset) -{ - LARGE_INTEGER file_offset; - IO_STATUS_BLOCK Iosb; - NTSTATUS Status; - KEVENT Event; - UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; - PMDL Mdl = (PMDL)MdlBase; - PPAGINGFILE PagingFile; - - DPRINT("MiReadSwapFile\n"); - - if (PageFileOffset == 0) - { - KeBugCheck(MEMORY_MANAGEMENT); - return(STATUS_UNSUCCESSFUL); - } - - ASSERT(PageFileIndex < MAX_PAGING_FILES); - - PagingFile = PagingFileList[PageFileIndex]; - - if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL) - { - DPRINT1("Bad paging file %u\n", PageFileIndex); - KeBugCheck(MEMORY_MANAGEMENT); - } - - MmInitializeMdl(Mdl, NULL, PAGE_SIZE); - MmBuildMdlFromPages(Mdl, &Page); - Mdl->MdlFlags |= MDL_PAGES_LOCKED; - - file_offset.QuadPart = PageFileOffset * PAGE_SIZE; - file_offset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, file_offset); - - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Status = IoPageRead(PagingFile->FileObject, - Mdl, - &file_offset, - &Event, - &Iosb); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Iosb.Status; - } - if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) - { - MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); - } - return(Status); + _In_ PFN_NUMBER Page, + _In_ const MMPTE* PointerPte +) +{ + LARGE_INTEGER FileOffset; + IO_STATUS_BLOCK Iosb; + ULONG PageFileIndex = PointerPte->u.Soft.PageFileLow; + ULONG_PTR PageFileOffset = PointerPte->u.Soft.PageFileHigh; + NTSTATUS Status; + KEVENT Event; + UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)]; + PMDL Mdl = (PMDL)MdlBase; + PPAGINGFILE PagingFile; + + DPRINT("MiReadPageFile\n"); + + if (PageFileOffset == 0) + { + KeBugCheck(MEMORY_MANAGEMENT); + return(STATUS_UNSUCCESSFUL); + } + + /* Normalize it */ + PageFileOffset--; + + ASSERT(PageFileIndex < MAX_PAGING_FILES); + + PagingFile = PagingFileList[PageFileIndex]; + + if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL) + { + DPRINT1("Bad paging file %u\n", PageFileIndex); + KeBugCheck(MEMORY_MANAGEMENT); + } + + MmInitializeMdl(Mdl, NULL, PAGE_SIZE); + MmBuildMdlFromPages(Mdl, &Page); + Mdl->MdlFlags |= MDL_PAGES_LOCKED; + + FileOffset.QuadPart = PageFileOffset * PAGE_SIZE; + FileOffset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, FileOffset); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Status = IoPageRead(PagingFile->FileObject, + Mdl, + &FileOffset, + &Event, + &Iosb); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = Iosb.Status; + } + if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) + { + MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); + } + return(Status); }
NTSTATUS @@ -411,19 +377,47 @@ _In_ PMMPTE PointerPte ) { - ULONG i; - - KeInitializeSpinLock(&PagingFileListLock); - - MiFreeSwapPages = 0; - MiUsedSwapPages = 0; - MiReservedSwapPages = 0; - - for (i = 0; i < MAX_PAGING_FILES; i++) - { - PagingFileList[i] = NULL; - } - MmNumberOfPagingFiles = 0; + ULONG PageFileIndex; + ULONG_PTR PageFileOffset; + PPAGINGFILE PageFile; + + /* Some sanity checks */ + ASSERT(PointerPte->u.Hard.Valid == 0); + ASSERT(PointerPte->u.Soft.Transition == 0); + ASSERT(PointerPte->u.Soft.Prototype == 0); + + /* We must hold the PFN lock */ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + PageFileIndex = PointerPte->u.Soft.PageFileLow; + PageFileOffset = PointerPte->u.Soft.PageFileHigh; + + /* Fix up the value */ + ASSERT(PageFileOffset != 0); + PageFileOffset--; + + DPRINT1("Releasing page file entry %u, %lu\n", PageFileIndex, PageFileOffset); + + ASSERT(PageFileIndex < MAX_PAGING_FILES); + + PageFile = PagingFileList[PageFileIndex]; + + /* And also lock this pagefile */ + KeAcquireSpinLockAtDpcLevel(&PageFile->AllocMapLock); + + /* It must be already in use */ + ASSERT(RtlTestBit(&PageFile->AllocBitMap, PageFileOffset)); + RtlClearBit(&PageFile->AllocBitMap, PageFileOffset); + + /* One more */ + PageFile->FreePages++; + PageFile->UsedPages--; + + MiFreeSwapPages++; + MiUsedSwapPages--; + + /* Done */ + KeReleaseSpinLockFromDpcLevel(&PageFile->AllocMapLock); }
NTSTATUS @@ -432,28 +426,51 @@ _Out_ PMMPTE PointerPte ) { - KIRQL oldIrql; - ULONG i, j; - - KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql); - - for (i = 0; i < PagingFile->AllocMapSize; i++) + ULONG PageFileIndex; + ULONG_PTR PageFileOffset; + PPAGINGFILE PageFile; + + /* We must hold the PFN lock */ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + for (PageFileIndex = 0; PageFileIndex < MAX_PAGING_FILES; PageFileIndex++) { - for (j = 0; j < 32; j++) - { - if (!(PagingFile->AllocMap[i] & (1 << j))) - { - PagingFile->AllocMap[i] |= (1 << j); - PagingFile->UsedPages++; - PagingFile->FreePages--; - KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); - return((i * 32) + j); - } - } + if (PagingFileList[PageFileIndex] == NULL) + continue; + if (PagingFileList[PageFileIndex]->FreePages != 0) + break; }
- KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); - return(0xFFFFFFFF); + if (PageFileIndex == MAX_PAGING_FILES) + { + DPRINT1("Pagefiles are full!\n"); + return STATUS_PAGEFILE_QUOTA; + } + + PointerPte->u.Long = 0; + + PageFile = PagingFileList[PageFileIndex]; + + /* And also lock this page file */ + KeAcquireSpinLockAtDpcLevel(&PageFile->AllocMapLock); + + /* Find a free entry in this page file */ + PageFileOffset = RtlFindClearBitsAndSet(&PageFile->AllocBitMap, 1, PageFile->AllocBitMapHint); + + /* We must have found something as the file was marked as having free entries */ + ASSERT(PageFileOffset != ~((ULONG_PTR)0)); + PageFile->AllocBitMapHint = PageFileOffset & ~((PageFile->MaximumSize / PAGE_SIZE) - 1); + + DPRINT1("Reserving page file entry %lu, %Iu\n", PageFileIndex, PageFileOffset); + + /* Done */ + KeReleaseSpinLockFromDpcLevel(&PageFile->AllocMapLock); + + /* We rely on PageFileHigh being != 0 */ + PointerPte->u.Soft.PageFileHigh = PageFileOffset + 1; + PointerPte->u.Soft.PageFileLow = PageFileIndex; + + return STATUS_SUCCESS; }
VOID @@ -461,89 +478,70 @@ NTAPI MmInitPagingFile(VOID) { - ULONG i; - ULONG_PTR off; - KIRQL oldIrql; - - i = FILE_FROM_ENTRY(Entry); - off = OFFSET_FROM_ENTRY(Entry); - - KeAcquireSpinLock(&PagingFileListLock, &oldIrql); - if (PagingFileList[i] == NULL) - { - KeBugCheck(MEMORY_MANAGEMENT); - } - KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock); - - PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32))); - - PagingFileList[i]->FreePages++; - PagingFileList[i]->UsedPages--; - - MiFreeSwapPages++; - MiUsedSwapPages--; - - KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock); - KeReleaseSpinLock(&PagingFileListLock, oldIrql); + ULONG i; + + MiFreeSwapPages = 0; + MiUsedSwapPages = 0; + MiReservedSwapPages = 0; + + for (i = 0; i < MAX_PAGING_FILES; i++) + { + PagingFileList[i] = NULL; + } + MmNumberOfPagingFiles = 0; +} + +VOID +NTAPI +MmFreeSwapPage(SWAPENTRY Entry) +{ + MMPTE TempPte; + KIRQL OldIrql; + + TempPte.u.Long = 0; + TempPte.u.Soft.PageFileLow = FILE_FROM_ENTRY(Entry); + TempPte.u.Soft.PageFileHigh = OFFSET_FROM_ENTRY(Entry); + + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + MiFreePageFileEntry(&TempPte); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); }
SWAPENTRY NTAPI MmAllocSwapPage(VOID) { - KIRQL oldIrql; - ULONG i; - ULONG off; + MMPTE TempPte; SWAPENTRY entry; - - KeAcquireSpinLock(&PagingFileListLock, &oldIrql); - - if (MiFreeSwapPages == 0) - { - KeReleaseSpinLock(&PagingFileListLock, oldIrql); - return(0); - } - - for (i = 0; i < MAX_PAGING_FILES; i++) - { - if (PagingFileList[i] != NULL && - PagingFileList[i]->FreePages >= 1) - { - off = MiAllocPageFromPagingFile(PagingFileList[i]); - if (off == 0xFFFFFFFF) - { - KeBugCheck(MEMORY_MANAGEMENT); - KeReleaseSpinLock(&PagingFileListLock, oldIrql); - return(STATUS_UNSUCCESSFUL); - } - MiUsedSwapPages++; - MiFreeSwapPages--; - KeReleaseSpinLock(&PagingFileListLock, oldIrql); - - entry = ENTRY_FROM_FILE_OFFSET(i, off); - return(entry); - } - } - - KeReleaseSpinLock(&PagingFileListLock, oldIrql); - KeBugCheck(MEMORY_MANAGEMENT); - return(0); + NTSTATUS Status; + KIRQL OldIrql; + + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + Status = MiReservePageFileEntry(&TempPte); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + if (!NT_SUCCESS(Status)) + return 0; + + entry = ENTRY_FROM_FILE_OFFSET(TempPte.u.Soft.PageFileLow, TempPte.u.Soft.PageFileHigh); + + return entry; }
static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL MmAllocRetrievelDescriptorList(ULONG Pairs) { - ULONG Size; - PRETRIEVEL_DESCRIPTOR_LIST RetDescList; - - Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER); - RetDescList = ExAllocatePool(NonPagedPool, Size); - if (RetDescList) - { - RtlZeroMemory(RetDescList, Size); - } - - return RetDescList; + ULONG Size; + PRETRIEVEL_DESCRIPTOR_LIST RetDescList; + + Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER); + RetDescList = ExAllocatePool(NonPagedPool, Size); + if (RetDescList) + { + RtlZeroMemory(RetDescList, Size); + } + + return RetDescList; }
NTSTATUS NTAPI @@ -552,340 +550,341 @@ IN PLARGE_INTEGER MaximumSize, IN ULONG Reserved) { - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE FileHandle; - IO_STATUS_BLOCK IoStatus; - PFILE_OBJECT FileObject; - PPAGINGFILE PagingFile; - KIRQL oldIrql; - ULONG AllocMapSize; - FILE_FS_SIZE_INFORMATION FsSizeInformation; - PRETRIEVEL_DESCRIPTOR_LIST RetDescList; - PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList; - ULONG i; - ULONG BytesPerAllocationUnit; - LARGE_INTEGER Vcn; - ULONG ExtentCount; - LARGE_INTEGER MaxVcn; - ULONG Count; - ULONG Size; - KPROCESSOR_MODE PreviousMode; - UNICODE_STRING CapturedFileName; - LARGE_INTEGER SafeInitialSize, SafeMaximumSize; - - DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n", - FileName, InitialSize->QuadPart); - - if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) - { - return(STATUS_TOO_MANY_PAGING_FILES); - } - - PreviousMode = ExGetPreviousMode(); - - if (PreviousMode != KernelMode) - { - _SEH2_TRY - { - SafeInitialSize = ProbeForReadLargeInteger(InitialSize); - SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - /* Return the exception code */ - _SEH2_YIELD(return _SEH2_GetExceptionCode()); - } - _SEH2_END; - } - else - { - SafeInitialSize = *InitialSize; - SafeMaximumSize = *MaximumSize; - } - - /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be - smaller than the maximum */ - if (0 != SafeInitialSize.u.HighPart) - { - return STATUS_INVALID_PARAMETER_2; - } - if (0 != SafeMaximumSize.u.HighPart) - { - return STATUS_INVALID_PARAMETER_3; - } - if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart) - { - return STATUS_INVALID_PARAMETER_MIX; - } - - Status = ProbeAndCaptureUnicodeString(&CapturedFileName, - PreviousMode, - FileName); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - InitializeObjectAttributes(&ObjectAttributes, - &CapturedFileName, - OBJ_KERNEL_HANDLE, + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE FileHandle; + IO_STATUS_BLOCK IoStatus; + PFILE_OBJECT FileObject; + PPAGINGFILE PagingFile; + KIRQL OldIrql; + ULONG AllocMapSize; + FILE_FS_SIZE_INFORMATION FsSizeInformation; + PRETRIEVEL_DESCRIPTOR_LIST RetDescList; + PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList; + ULONG i; + ULONG BytesPerAllocationUnit; + LARGE_INTEGER Vcn; + ULONG ExtentCount; + LARGE_INTEGER MaxVcn; + ULONG Count; + ULONG Size; + KPROCESSOR_MODE PreviousMode; + UNICODE_STRING CapturedFileName; + LARGE_INTEGER SafeInitialSize, SafeMaximumSize; + + DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n", + FileName, InitialSize->QuadPart); + + if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) + { + return(STATUS_TOO_MANY_PAGING_FILES); + } + + PreviousMode = ExGetPreviousMode(); + + if (PreviousMode != KernelMode) + { + _SEH2_TRY + { + SafeInitialSize = ProbeForReadLargeInteger(InitialSize); + SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + } + else + { + SafeInitialSize = *InitialSize; + SafeMaximumSize = *MaximumSize; + } + + /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be + smaller than the maximum */ + if (0 != SafeInitialSize.u.HighPart) + { + return STATUS_INVALID_PARAMETER_2; + } + if (0 != SafeMaximumSize.u.HighPart) + { + return STATUS_INVALID_PARAMETER_3; + } + if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart) + { + return STATUS_INVALID_PARAMETER_MIX; + } + + Status = ProbeAndCaptureUnicodeString(&CapturedFileName, + PreviousMode, + FileName); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + InitializeObjectAttributes(&ObjectAttributes, + &CapturedFileName, + 0, + NULL, + NULL); + + Status = IoCreateFile(&FileHandle, + FILE_ALL_ACCESS, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + 0, + FILE_OPEN_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0, + CreateFileTypeNone, + NULL, + SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); + + ReleaseCapturedUnicodeString(&CapturedFileName, + PreviousMode); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + Status = ZwQueryVolumeInformationFile(FileHandle, + &IoStatus, + &FsSizeInformation, + sizeof(FILE_FS_SIZE_INFORMATION), + FileFsSizeInformation); + if (!NT_SUCCESS(Status)) + { + ZwClose(FileHandle); + return Status; + } + + BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * + FsSizeInformation.BytesPerSector; + /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is + * a problem if the paging file is fragmented. Suppose the first cluster + * of the paging file is cluster 3042 but cluster 3043 is NOT part of the + * paging file but of another file. We can't write a complete page (4096 + * bytes) to the physical location of cluster 3042 then. */ + if (BytesPerAllocationUnit % PAGE_SIZE) + { + DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n", + BytesPerAllocationUnit, PAGE_SIZE); + ZwClose(FileHandle); + return STATUS_UNSUCCESSFUL; + } + + Status = ZwSetInformationFile(FileHandle, + &IoStatus, + &SafeInitialSize, + sizeof(LARGE_INTEGER), + FileAllocationInformation); + if (!NT_SUCCESS(Status)) + { + ZwClose(FileHandle); + return(Status); + } + + Status = ObReferenceObjectByHandle(FileHandle, + FILE_ALL_ACCESS, + IoFileObjectType, + PreviousMode, + (PVOID*)&FileObject, + NULL); + if (!NT_SUCCESS(Status)) + { + ZwClose(FileHandle); + return(Status); + } + + CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); + + if (CurrentRetDescList == NULL) + { + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(STATUS_NO_MEMORY); + } + +#if defined(__GNUC__) + Vcn.QuadPart = 0LL; +#else + Vcn.QuadPart = 0; +#endif + + ExtentCount = 0; + MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit; + while(1) + { + Status = ZwFsControlFile(FileHandle, + 0, NULL, - NULL); - - Status = IoCreateFile(&FileHandle, - FILE_ALL_ACCESS, - &ObjectAttributes, - &IoStatus, - NULL, - 0, - 0, - FILE_OPEN_IF, - FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0, - CreateFileTypeNone, - NULL, - SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); - - ReleaseCapturedUnicodeString(&CapturedFileName, - PreviousMode); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Status = ZwQueryVolumeInformationFile(FileHandle, - &IoStatus, - &FsSizeInformation, - sizeof(FILE_FS_SIZE_INFORMATION), - FileFsSizeInformation); - if (!NT_SUCCESS(Status)) - { - ZwClose(FileHandle); - return Status; - } - - BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * - FsSizeInformation.BytesPerSector; - /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is - * a problem if the paging file is fragmented. Suppose the first cluster - * of the paging file is cluster 3042 but cluster 3043 is NOT part of the - * paging file but of another file. We can't write a complete page (4096 - * bytes) to the physical location of cluster 3042 then. */ - if (BytesPerAllocationUnit % PAGE_SIZE) - { - DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n", - BytesPerAllocationUnit, PAGE_SIZE); - ZwClose(FileHandle); - return STATUS_UNSUCCESSFUL; - } - - Status = ZwSetInformationFile(FileHandle, - &IoStatus, - &SafeInitialSize, - sizeof(LARGE_INTEGER), - FileAllocationInformation); - if (!NT_SUCCESS(Status)) - { - ZwClose(FileHandle); - return(Status); - } - - Status = ObReferenceObjectByHandle(FileHandle, - FILE_ALL_ACCESS, - IoFileObjectType, - KernelMode, - (PVOID*)&FileObject, - NULL); - if (!NT_SUCCESS(Status)) - { - ZwClose(FileHandle); - return(Status); - } - - CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); - - if (CurrentRetDescList == NULL) - { - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_NO_MEMORY); - } - -#if defined(__GNUC__) - Vcn.QuadPart = 0LL; -#else - Vcn.QuadPart = 0; -#endif - - ExtentCount = 0; - MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit; - while(1) - { - Status = ZwFsControlFile(FileHandle, - 0, - NULL, - NULL, - &IoStatus, - FSCTL_GET_RETRIEVAL_POINTERS, - &Vcn, - sizeof(LARGE_INTEGER), - &CurrentRetDescList->RetrievalPointers, - sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER)); - if (!NT_SUCCESS(Status)) - { + NULL, + &IoStatus, + FSCTL_GET_RETRIEVAL_POINTERS, + &Vcn, + sizeof(LARGE_INTEGER), + &CurrentRetDescList->RetrievalPointers, + sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER)); + if (!NT_SUCCESS(Status)) + { + while (RetDescList) + { + CurrentRetDescList = RetDescList; + RetDescList = RetDescList->Next; + ExFreePool(CurrentRetDescList); + } + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(Status); + } + ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount; + if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart) + { + CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); + if (CurrentRetDescList->Next == NULL) + { while (RetDescList) { - CurrentRetDescList = RetDescList; - RetDescList = RetDescList->Next; - ExFreePool(CurrentRetDescList); + CurrentRetDescList = RetDescList; + RetDescList = RetDescList->Next; + ExFreePool(CurrentRetDescList); } ObDereferenceObject(FileObject); ZwClose(FileHandle); - return(Status); - } - ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount; - if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart) - { - CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); - if (CurrentRetDescList->Next == NULL) - { - while (RetDescList) - { - CurrentRetDescList = RetDescList; - RetDescList = RetDescList->Next; - ExFreePool(CurrentRetDescList); - } - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_NO_MEMORY); - } - Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn; - CurrentRetDescList = CurrentRetDescList->Next; - } - else - { - break; - } - } - - PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile)); - if (PagingFile == NULL) - { - while (RetDescList) - { - CurrentRetDescList = RetDescList; - RetDescList = RetDescList->Next; - ExFreePool(CurrentRetDescList); - } - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_NO_MEMORY); - } - - RtlZeroMemory(PagingFile, sizeof(*PagingFile)); - - PagingFile->FileObject = FileObject; - PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart; - PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart; - PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE); - PagingFile->UsedPages = 0; - KeInitializeSpinLock(&PagingFile->AllocMapLock); - - AllocMapSize = (PagingFile->FreePages / 32) + 1; - PagingFile->AllocMap = ExAllocatePool(NonPagedPool, - AllocMapSize * sizeof(ULONG)); - PagingFile->AllocMapSize = AllocMapSize; - - if (PagingFile->AllocMap == NULL) - { - while (RetDescList) - { - CurrentRetDescList = RetDescList; - RetDescList = RetDescList->Next; - ExFreePool(CurrentRetDescList); - } - ExFreePool(PagingFile); - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_NO_MEMORY); - } - DPRINT("ExtentCount: %lu\n", ExtentCount); - Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER); - PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size); - if (PagingFile->RetrievalPointers == NULL) - { - while (RetDescList) - { - CurrentRetDescList = RetDescList; - RetDescList = RetDescList->Next; - ExFreePool(CurrentRetDescList); - } - ExFreePool(PagingFile->AllocMap); - ExFreePool(PagingFile); - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_NO_MEMORY); - } - - RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG)); - RtlZeroMemory(PagingFile->RetrievalPointers, Size); - - Count = 0; - PagingFile->RetrievalPointers->ExtentCount = ExtentCount; - PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn; - CurrentRetDescList = RetDescList; - while (CurrentRetDescList) - { - memcpy(&PagingFile->RetrievalPointers->Extents[Count], - CurrentRetDescList->RetrievalPointers.Extents, - CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER)); - Count += CurrentRetDescList->RetrievalPointers.ExtentCount; - RetDescList = CurrentRetDescList; - CurrentRetDescList = CurrentRetDescList->Next; - ExFreePool(RetDescList); - } - - if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount || - PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart) - { - ExFreePool(PagingFile->RetrievalPointers); - ExFreePool(PagingFile->AllocMap); - ExFreePool(PagingFile); - ObDereferenceObject(FileObject); - ZwClose(FileHandle); - return(STATUS_UNSUCCESSFUL); - } - - /* - * Change the entries from lcn's to volume offset's. - */ - PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit; - for (i = 0; i < ExtentCount; i++) - { - PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit; - PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit; - } - - KeAcquireSpinLock(&PagingFileListLock, &oldIrql); - for (i = 0; i < MAX_PAGING_FILES; i++) - { - if (PagingFileList[i] == NULL) - { - PagingFileList[i] = PagingFile; - break; - } - } - MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages; - MmNumberOfPagingFiles++; - KeReleaseSpinLock(&PagingFileListLock, oldIrql); - - ZwClose(FileHandle); - - MmSwapSpaceMessage = FALSE; - - return(STATUS_SUCCESS); + return(STATUS_NO_MEMORY); + } + Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn; + CurrentRetDescList = CurrentRetDescList->Next; + } + else + { + break; + } + } + + PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile)); + if (PagingFile == NULL) + { + while (RetDescList) + { + CurrentRetDescList = RetDescList; + RetDescList = RetDescList->Next; + ExFreePool(CurrentRetDescList); + } + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(STATUS_NO_MEMORY); + } + + RtlZeroMemory(PagingFile, sizeof(*PagingFile)); + + PagingFile->FileObject = FileObject; + PagingFile->MaximumSize = SafeMaximumSize.LowPart; + PagingFile->CurrentSize = SafeInitialSize.LowPart; + PagingFile->FreePages = (ULONG)(SafeMaximumSize.LowPart / PAGE_SIZE); + PagingFile->UsedPages = 0; + KeInitializeSpinLock(&PagingFile->AllocMapLock); + + AllocMapSize = (PagingFile->FreePages / 32) + 1; + PagingFile->AllocMap = ExAllocatePool(NonPagedPool, + AllocMapSize * sizeof(ULONG)); + + if (PagingFile->AllocMap == NULL) + { + while (RetDescList) + { + CurrentRetDescList = RetDescList; + RetDescList = RetDescList->Next; + ExFreePool(CurrentRetDescList); + } + ExFreePool(PagingFile); + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(STATUS_NO_MEMORY); + } + DPRINT("ExtentCount: %lu\n", ExtentCount); + Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER); + PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size); + if (PagingFile->RetrievalPointers == NULL) + { + while (RetDescList) + { + CurrentRetDescList = RetDescList; + RetDescList = RetDescList->Next; + ExFreePool(CurrentRetDescList); + } + ExFreePool(PagingFile->AllocMap); + ExFreePool(PagingFile); + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(STATUS_NO_MEMORY); + } + + RtlZeroMemory(PagingFile->RetrievalPointers, Size); + + RtlInitializeBitMap(&PagingFile->AllocBitMap, PagingFile->AllocMap, AllocMapSize * 32); + RtlClearAllBits(&PagingFile->AllocBitMap); + + Count = 0; + PagingFile->RetrievalPointers->ExtentCount = ExtentCount; + PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn; + CurrentRetDescList = RetDescList; + while (CurrentRetDescList) + { + memcpy(&PagingFile->RetrievalPointers->Extents[Count], + CurrentRetDescList->RetrievalPointers.Extents, + CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER)); + Count += CurrentRetDescList->RetrievalPointers.ExtentCount; + RetDescList = CurrentRetDescList; + CurrentRetDescList = CurrentRetDescList->Next; + ExFreePool(RetDescList); + } + + if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount || + PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart) + { + ExFreePool(PagingFile->RetrievalPointers); + ExFreePool(PagingFile->AllocMap); + ExFreePool(PagingFile); + ObDereferenceObject(FileObject); + ZwClose(FileHandle); + return(STATUS_UNSUCCESSFUL); + } + + /* + * Change the entries from lcn's to volume offset's. + */ + PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit; + for (i = 0; i < ExtentCount; i++) + { + PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit; + PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit; + } + + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + for (i = 0; i < MAX_PAGING_FILES; i++) + { + if (PagingFileList[i] == NULL) + { + PagingFileList[i] = PagingFile; + break; + } + } + MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages; + MmNumberOfPagingFiles++; + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + ZwClose(FileHandle); + + MmSwapSpaceMessage = FALSE; + + return(STATUS_SUCCESS); }
/* EOF */