test: deleteva.c File Reference

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

# deleteva.c File Reference

`#include "mi.h"`

Go to the source code of this file.

## Functions

VOID | MiDeleteVirtualAddresses (IN PUCHAR StartingAddress, IN PUCHAR EndingAddress, IN ULONG AddressSpaceDeletion, IN PMMVAD Vad)
VOID | MiDeletePte (IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN ULONG AddressSpaceDeletion, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte, IN PMMPTE_FLUSH_LIST PteFlushList OPTIONAL)
ULONG FASTCALL | MiReleasePageFileSpace (IN MMPTE PteContents)
VOID FASTCALL | MiUpdateModifiedWriterMdls (IN ULONG PageFileNumber)
VOID | MiFlushPteList (IN PMMPTE_FLUSH_LIST PteFlushList, IN ULONG AllProcessors, IN MMPTE FillPte)

## Function Documentation

VOID MiDeletePte | ( | IN PMMPTE | PointerPte,
|  | IN PVOID | VirtualAddress,
|  | IN ULONG | AddressSpaceDeletion,
|  | IN PEPROCESS | CurrentProcess,
|  | IN PMMPTE | PrototypePte,
|  | IN PMMPTE_FLUSH_LIST PteFlushList | OPTIONAL
| ) |

Definition at line 506 of file deleteva.c.

References ASSERT, DbgPrint, _MMWSLE::e1, FALSE, _MMWSL::FirstDynamic, FreePageList, KeBugCheckEx(), KeFlushSingleTb(), _MMWSLENTRY::LockedInMemory, _MMWSLENTRY::LockedInWs, MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_PFN_ELEMENT, MI_PTE_LOOKUP_NEEDED, MI_SET_PFN_DELETED, MI_WRITE_INVALID_PTE, MiCheckPdeForPagedPool(), MiDecrementCloneBlockReference(), MiDecrementShareAndValidCount, MiDecrementShareCount(), MiDecrementShareCountOnly, MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiFlushPteList(), MiFormatPfn(), MiFormatPte(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiHighestUserPte, MiInsertPageInList(), MiLocateCloneAddress, MiLocateWsle(), MiPteToProto, MiReleasePageFileSpace(), MiReleaseWsle(), MiRemoveWsle(), MiSwapWslEntries(), MiUnlinkPageFromList(), MM_DBG_PTE_UPDATE, MM_MAXIMUM_FLUSH_COUNT, MM_PFN_LOCK_ASSERT, MmPageLocationList, MmWorkingSetList, MmWsle, MMWSLENTRY, NT_SUCCESS, NULL, _MMPFN::OriginalPte, PAGE_ALIGN, PMMCLONE_BLOCK, PMMCLONE_DESCRIPTOR, PMMPTE_FLUSH_LIST, PrototypePte, _MMPFN::PteAddress, _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMPFN::u1, _MMWSLE::u1, _MMPFN::u2, _MMPFN::u3, _MMWSLENTRY::Valid, WSLE_NULL_INDEX, and ZeroPte.

Referenced by MiDecommitPages(), MiDeletePageTablesForPhysicalRange(), MiDeleteVirtualAddresses(), MiGrowWsleHash(), MiRemoveMappedView(), MiRemoveWorkingSetPages(), MiUnmapLockedPagesInUserSpace(), and MmCleanProcessAddressSpace().

    00517                    :
    00518
    00519     This routine deletes the contents of the specified PTE.  The PTE
    00520     can be in one of the following states:
    00521
    00522         - active and valid
    00523         - transition
    00524         - in paging file
    00525         - in prototype PTE format
    00526
    00527 Arguments:
    00528
    00529     PointerPte - Supplies a pointer to the PTE to delete.
    00530
    00531     VirtualAddress - Supplies the virtual address which corresponds to
    00532                      the PTE.  This is used to locate the working set entry
    00533                      to eliminate it.
    00534
    00535     AddressSpaceDeletion - Supplies TRUE if the address space is being
    00536                            deleted, FALSE otherwise.  If TRUE is specified
    00537                            the TB is not flushed and valid addresses are
    00538                            not removed from the working set.
    00539
    00540
    00541     CurrentProcess - Supplies a pointer to the current process.
    00542
    00543     PrototypePte - Supplies a pointer to the prototype PTE which currently
    00544                    or originally mapped this page.  This is used to determine
    00545                    if the PTE is a fork PTE and should have its reference block
    00546                    decremented.
    00547
    00548 Return Value:
    00549
    00550     None.
    00551
    00552 Environment:
    00553
    00554     Kernel mode, APCs disabled, PFN lock and working set mutex held.
    00555
    00556 --*/
    00557
    00558 {
    00559     PMMPTE PointerPde;
    00560     PMMPTE PointerPpe;
    00561     PMMPFN Pfn1;
    00562     PMMPFN Pfn2;
    00563     MMPTE PteContents;
    00564     ULONG WorkingSetIndex;
    00565     ULONG Entry;
    00566     PVOID SwapVa;
    00567     MMWSLENTRY Locked;
    00568     ULONG WsPfnIndex;
    00569     PMMCLONE_BLOCK CloneBlock;
    00570     PMMCLONE_DESCRIPTOR CloneDescriptor;
    00571     ULONG Waited;
    00572
    00573     MM_PFN_LOCK_ASSERT();
    00574
    00575 #if DBG
    00576     if (MmDebug & MM_DBG_PTE_UPDATE) {
    00577         DbgPrint("deleting PTE\n");
    00578         MiFormatPte(PointerPte);
    00579     }
    00580 #endif //DBG
    00581
    00582     PteContents = *PointerPte;
    00583
    00584     if (PteContents.u.Hard.Valid == 1) {
    00585
    00586 #ifdef _X86_
    00587 #if DBG
    00588 #if !defined(NT_UP)
    00589
    00590         if (PteContents.u.Hard.Writable == 1) {
    00591             ASSERT (PteContents.u.Hard.Dirty == 1);
    00592         }
    00593         ASSERT (PteContents.u.Hard.Accessed == 1);
    00594 #endif //NTUP
    00595 #endif //DBG
    00596 #endif //X86
    00597
    00598         //
    00599         // PTE is valid.  Check PFN database to see if this is a prototype PTE.
    00600         //
    00601
    00602         Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
    00603         WsPfnIndex = Pfn1->u1.WsIndex;
    00604
    00605 #if DBG
    00606         if (MmDebug & MM_DBG_PTE_UPDATE) {
    00607             MiFormatPfn(Pfn1);
    00608         }
    00609 #endif //DBG
    00610
    00611         CloneDescriptor = NULL;
    00612
    00613         if (Pfn1->u3.e1.PrototypePte == 1) {
    00614
    00615             CloneBlock = (PMMCLONE_BLOCK)Pfn1->PteAddress;
    00616
    00617             //
    00618             // Capture the state of the modified bit for this PTE.
    00619             //
    00620
    00621             MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1);
    00622
    00623             //
    00624             // Decrement the share and valid counts of the page table
    00625             // page which maps this PTE.
    00626             //
    00627
    00628             PointerPde = MiGetPteAddress (PointerPte);
    00629             if (PointerPde->u.Hard.Valid == 0) {
    00630 #if !defined (_WIN64)
    00631                 if (!NT_SUCCESS(MiCheckPdeForPagedPool (PointerPte))) {
    00632 #endif
    00633                     KeBugCheckEx (MEMORY_MANAGEMENT,
    00634                                   0x61940,
    00635                                   (ULONG_PTR)PointerPte,
    00636                                   (ULONG_PTR)PointerPde->u.Long,
    00637                                   (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPte));
    00638 #if !defined (_WIN64)
    00639                 }
    00640 #endif
    00641             }
    00642             MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde));
    00643
    00644             //
    00645             // Decrement the share count for the physical page.
    00646             //
    00647
    00648             MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents));
    00649
    00650             //
    00651             // Check to see if this is a fork prototype PTE and if so
    00652             // update the clone descriptor address.
    00653             //
    00654
    00655             if (PointerPte <= MiHighestUserPte) {
    00656
    00657                 if (PrototypePte != Pfn1->PteAddress) {
    00658
    00659                     //
    00660                     // Locate the clone descriptor within the clone tree.
    00661                     //
    00662
    00663                     CloneDescriptor = MiLocateCloneAddress ((PVOID)CloneBlock);
    00664
    00665 #if DBG
    00666                     if (CloneDescriptor == NULL) {
    00667                         DbgPrint("1PrototypePte %p Clone desc %p pfn pte addr %p\n",
    00668                         PrototypePte, CloneDescriptor, Pfn1->PteAddress);
    00669                         MiFormatPte(PointerPte);
    00670                         ASSERT (FALSE);
    00671                     }
    00672 #endif // DBG
    00673
    00674                 }
    00675             }
    00676         } else {
    00677
    00678             ASSERT (Pfn1->u2.ShareCount == 1);
    00679
    00680             //
    00681             // This PTE is a NOT a prototype PTE, delete the physical page.
    00682             //
    00683
    00684             //
    00685             // Decrement the share and valid counts of the page table
    00686             // page which maps this PTE.
    00687             //
    00688
    00689             MiDecrementShareAndValidCount (Pfn1->PteFrame);
    00690
    00691             MI_SET_PFN_DELETED (Pfn1);
    00692
    00693             //
    00694             // Decrement the share count for the physical page.  As the page
    00695             // is private it will be put on the free list.
    00696             //
    00697
    00698             MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents));
    00699
    00700             //
    00701             // Decrement the count for the number of private pages.
    00702             //
    00703
    00704             CurrentProcess->NumberOfPrivatePages -= 1;
    00705         }
    00706
    00707         //
    00708         // Find the WSLE for this page and eliminate it.
    00709         //
    00710
    00711         //
    00712         // If we are deleting the system portion of the address space, do
    00713         // not remove WSLEs or flush translation buffers as there can be
    00714         // no other usage of this address space.
    00715         //
    00716
    00717         if (AddressSpaceDeletion == FALSE) {
    00718
    00719             WorkingSetIndex = MiLocateWsle (VirtualAddress,
    00720                                             MmWorkingSetList,
    00721                                             WsPfnIndex );
    00722
    00723             ASSERT (WorkingSetIndex != WSLE_NULL_INDEX);
    00724
    00725             //
    00726             // Check to see if this entry is locked in the working set
    00727             // or locked in memory.
    00728             //
    00729
    00730             Locked = MmWsle[WorkingSetIndex].u1.e1;
    00731
    00732             MiRemoveWsle (WorkingSetIndex, MmWorkingSetList);
    00733
    00734             //
    00735             // Add this entry to the list of free working set entries
    00736             // and adjust the working set count.
    00737             //
    00738
    00739             MiReleaseWsle (WorkingSetIndex, &CurrentProcess->Vm);
    00740
    00741             if ((Locked.LockedInWs == 1) || (Locked.LockedInMemory == 1)) {
    00742
    00743                 //
    00744                 // This entry is locked.
    00745                 //
    00746
    00747                 ASSERT (WorkingSetIndex < MmWorkingSetList->FirstDynamic);
    00748                 MmWorkingSetList->FirstDynamic -= 1;
    00749
    00750                 if (WorkingSetIndex != MmWorkingSetList->FirstDynamic) {
    00751
    00752                     Entry = MmWorkingSetList->FirstDynamic;
    00753                     ASSERT (MmWsle[Entry].u1.e1.Valid);
    00754                     SwapVa = MmWsle[Entry].u1.VirtualAddress;
    00755                     SwapVa = PAGE_ALIGN (SwapVa);
    00756                     Pfn2 = MI_PFN_ELEMENT (
    00757                               MiGetPteAddress (SwapVa)->u.Hard.PageFrameNumber);
    00758 #if 0
    00759                     Entry = MiLocateWsleAndParent (SwapVa,
    00760                                                    &Parent,
    00761                                                    MmWorkingSetList,
    00762                                                    Pfn2->u1.WsIndex);
    00763
    00764                     //
    00765                     // Swap the removed entry with the last locked entry
    00766                     // which is located at first dynamic.
    00767                     //
    00768
    00769                     MiSwapWslEntries (Entry,
    00770                                       Parent,
    00771                                       WorkingSetIndex,
    00772                                       MmWorkingSetList);
    00773 #endif //0
    00774
    00775                     MiSwapWslEntries (Entry,
    00776                                       WorkingSetIndex,
    00777                                       &CurrentProcess->Vm);
    00778                 }
    00779             } else {
    00780                 ASSERT (WorkingSetIndex >= MmWorkingSetList->FirstDynamic);
    00781             }
    00782
    00783             //
    00784             // Flush the entry out of the TB.
    00785             //
    00786
    00787             if (!ARGUMENT_PRESENT (PteFlushList)) {
    00788                 KeFlushSingleTb (VirtualAddress,
    00789                                  TRUE,
    00790                                  FALSE,
    00791                                  (PHARDWARE_PTE)PointerPte,
    00792                                  ZeroPte.u.Flush);
    00793             } else {
    00794                 if (PteFlushList->Count != MM_MAXIMUM_FLUSH_COUNT) {
    00795                     PteFlushList->FlushPte[PteFlushList->Count] = PointerPte;
    00796                     PteFlushList->FlushVa[PteFlushList->Count] = VirtualAddress;
    00797                     PteFlushList->Count += 1;
    00798                 }
    00799                 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
    00800             }
    00801
    00802             if (CloneDescriptor != NULL) {
    00803
    00804                 //
    00805                 // Flush PTEs as this could release the PFN_LOCK.
    00806                 //
    00807
    00808                 if (ARGUMENT_PRESENT (PteFlushList)) {
    00809                     MiFlushPteList (PteFlushList, FALSE, ZeroPte);
    00810                 }
    00811
    00812                 //
    00813                 // Decrement the reference count for the clone block,
    00814                 // note that this could release and reacquire
    00815                 // the mutexes hence cannot be done until after the
    00816                 // working set index has been removed.
    00817                 //
    00818
    00819                 if (MiDecrementCloneBlockReference ( CloneDescriptor,
    00820                                                      CloneBlock,
    00821                                                      CurrentProcess )) {
    00822
    00823                     //
    00824                     // The working set mutex was released.  This may
    00825                     // have removed the current page directory & table page.
    00826                     //
    00827
    00828                     PointerPpe = MiGetPteAddress (PointerPde);
    00829
    00830                     do {
    00831
    00832                         MiDoesPpeExistAndMakeValid (PointerPpe,
    00833                                                     CurrentProcess,
    00834                                                     TRUE,
    00835                                                     &Waited);
    00836
    00837                         Waited = 0;
    00838
    00839                         //
    00840                         // If the call below results in a PFN release and
    00841                         // reacquire, then we must redo them both.
    00842                         //
    00843
    00844                         MiDoesPdeExistAndMakeValid (PointerPde,
    00845                                                     CurrentProcess,
    00846                                                     TRUE,
    00847                                                     &Waited);
    00848
    00849                     } while (Waited != 0);
    00850                 }
    00851             }
    00852         }
    00853
    00854     } else if (PteContents.u.Soft.Prototype == 1) {
    00855
    00856         //
    00857         // This is a prototype PTE, if it is a fork PTE clean up the
    00858         // fork structures.
    00859         //
    00860
    00861         if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) {
    00862
    00863             //
    00864             // Check to see if the prototype PTE is a fork prototype PTE.
    00865             //
    00866
    00867             if (PointerPte <= MiHighestUserPte) {
    00868
    00869                 if (PrototypePte != MiPteToProto (PointerPte)) {
    00870
    00871                     CloneBlock = (PMMCLONE_BLOCK)MiPteToProto (PointerPte);
    00872                     CloneDescriptor = MiLocateCloneAddress ((PVOID)CloneBlock);
    00873
    00874
    00875 #if DBG
    00876                     if (CloneDescriptor == NULL) {
    00877                         DbgPrint("1PrototypePte %p Clone desc %p \n",
    00878                             PrototypePte, CloneDescriptor);
    00879                         MiFormatPte(PointerPte);
    00880                         ASSERT (FALSE);
    00881                     }
    00882 #endif //DBG
    00883
    00884                     //
    00885                     // Decrement the reference count for the clone block,
    00886                     // note that this could release and reacquire
    00887                     // the mutexes.
    00888                     //
    00889
    00890                     MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
    00891
    00892                     if (ARGUMENT_PRESENT (PteFlushList)) {
    00893                         MiFlushPteList (PteFlushList, FALSE, ZeroPte);
    00894                     }
    00895
    00896                     if (MiDecrementCloneBlockReference ( CloneDescriptor,
    00897                                                          CloneBlock,
    00898                                                          CurrentProcess )) {
    00899
    00900                         //
    00901                         // The working set mutex was released.  This may
    00902                         // have removed the current page directory & table page.
    00903                         //
    00904
    00905                         PointerPde = MiGetPteAddress (PointerPte);
    00906                         PointerPpe = MiGetPteAddress (PointerPde);
    00907
    00908                         //
    00909                         // If either call below results in a PFN release and
    00910                         // reacquire, then we must redo them both.
    00911                         //
    00912
    00913                         do {
    00914
    00915                             if (MiDoesPpeExistAndMakeValid (PointerPpe,
    00916                                                         CurrentProcess,
    00917                                                         TRUE,
    00918                                                         &Waited) == FALSE) {
    00919
    00920                                 //
    00921                                 // The PPE has been deleted when the PFN lock
    00922                                 // was released.  Just bail as the PDE/PTE are
    00923                                 // gone now anyway.
    00924                                 //
    00925
    00926                                 return;
    00927                             }
    00928
    00929                             Waited = 0;
    00930
    00931                             //
    00932                             // If the call below results in a PFN release and
    00933                             // reacquire, then we must redo them both.  If the
    00934                             // PDE was deleted when the PFN lock was released
    00935                             // then we just bail as the PTE is gone anyway.
    00936                             //
    00937
    00938                             if (MiDoesPdeExistAndMakeValid (PointerPde,
    00939                                                         CurrentProcess,
    00940                                                         TRUE,
    00941                                                         &Waited) == FALSE) {
    00942                                 return;
    00943                             }
    00944
    00945                         } while (Waited != 0);
    00946                     }
    00947                 }
    00948             }
    00949         }
    00950
    00951     } else if (PteContents.u.Soft.Transition == 1) {
    00952
    00953         //
    00954         // This is a transition PTE. (Page is private)
    00955         //
    00956
    00957         Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber);
    00958
    00959         MI_SET_PFN_DELETED (Pfn1);
    00960
    00961         MiDecrementShareCount (Pfn1->PteFrame);
    00962
    00963         //
    00964         // Check the reference count for the page, if the reference
    00965         // count is zero, move the page to the free list, if the reference
    00966         // count is not zero, ignore this page.  When the reference count
    00967         // goes to zero, it will be placed on the free list.
    00968         //
    00969
    00970         if (Pfn1->u3.e2.ReferenceCount == 0) {
    00971             MiUnlinkPageFromList (Pfn1);
    00972             MiReleasePageFileSpace (Pfn1->OriginalPte);
    00973             MiInsertPageInList (MmPageLocationList[FreePageList],
    00974                                 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents));
    00975         }
    00976
    00977         //
    00978         // Decrement the count for the number of private pages.
    00979         //
    00980
    00981         CurrentProcess->NumberOfPrivatePages -= 1;
    00982
    00983     } else {
    00984
    00985         //
    00986         // Must be page file space.
    00987         //
    00988
    00989         if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) {
    00990
    00991             if (MiReleasePageFileSpace (*PointerPte)) {
    00992
    00993                 //
    00994                 // Decrement the count for the number of private pages.
    00995                 //
    00996
    00997                 CurrentProcess->NumberOfPrivatePages -= 1;
    00998             }
    00999         }
    01000     }
    01001
    01002     //
    01003     // Zero the PTE contents.
    01004     //
    01005
    01006     MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
    01007
    01008     return;
    01009 }

VOID MiDeleteVirtualAddresses | ( | IN PUCHAR | StartingAddress,
|  | IN PUCHAR | EndingAddress,
|  | IN ULONG | AddressSpaceDeletion,
|  | IN PMMVAD | Vad
| ) |

Definition at line 26 of file deleteva.c.

References APC_LEVEL, _MMPTE_FLUSH_LIST::Count, DbgPrint, FALSE, IS_PTE_NOT_DEMAND_ZERO, LOCK_PFN, MI_DECREMENT_USED_PTES_BY_HANDLE, MI_GET_USED_PTES_FROM_HANDLE, MI_GET_USED_PTES_HANDLE, MI_VA_TO_VPN, MI_WRITE_INVALID_PTE, MiDeletePte(), MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiFlushPteList(), MiGetPdeAddress, MiGetPpeAddress, MiGetProtoPteAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteOnPdeBoundary, MiIsVirtualAddressOnPdeBoundary, MiIsVirtualAddressOnPpeBoundary, MiLocateSubsection(), MM_PFN_LOCK_ASSERT, NULL, PAGE_SIZE, PsGetCurrentProcess, _SUBSECTION::PtesInSubsection, _SUBSECTION::SubsectionBase, TRUE, _MMPTE::u, UNLOCK_PFN, and ZeroPte.

Referenced by MiDeleteFreeVm(), MiRemoveMappedView(), and MmCleanProcessAddressSpace().

    00035                    :
    00036
    00037     This routine deletes the specified virtual address range within
    00038     the current process.
    00039
    00040 Arguments:
    00041
    00042     StartingAddress - Supplies the first virtual address to delete.
    00043
    00044     EndingAddress - Supplies the last address to delete.
    00045
    00046     AddressSpaceDeletion - Supplies TRUE if the address space is being
    00047                            deleted, FALSE otherwise.  If TRUE is specified
    00048                            the TB is not flushed and valid addresses are
    00049                            not removed from the working set.
    00050
    00051     Vad - Supplies the virtual address descriptor which maps this range
    00052           or NULL if we are not concerned about views.  From the Vad the
    00053           range of prototype PTEs is determined and this information is
    00054           used to uncover if the PTE refers to a prototype PTE or a
    00055           fork PTE.
    00056
    00057 Return Value:
    00058
    00059     None.
    00060
    00061
    00062 Environment:
    00063
    00064     Kernel mode, called with APCs disabled, working set mutex and PFN lock
    00065     held.  These mutexes may be released and reacquired to fault pages in.
    00066
    00067 --*/
    00068
    00069 {
    00070     PUCHAR Va;
    00071     PUCHAR FirstValidVa;
    00072     PVOID TempVa;
    00073     PMMPTE PointerPte;
    00074     PMMPTE PointerPde;
    00075     PMMPTE PointerPpe;
    00076     PMMPTE OriginalPointerPte;
    00077     PMMPTE ProtoPte;
    00078     PMMPTE ProtoPte2;
    00079     PMMPTE LastProtoPte;
    00080     PMMPTE LastProtoPte2;
    00081     PEPROCESS CurrentProcess;
    00082     PSUBSECTION Subsection;
    00083     PVOID UsedPageTableHandle;
    00084     PVOID UsedPageDirectoryHandle;
    00085     KIRQL OldIrql;
    00086     MMPTE_FLUSH_LIST FlushList;
    00087     ULONG Waited;
    00088     LOGICAL Skipped;
    00089
    00090     OldIrql = APC_LEVEL;
    00091     FlushList.Count = 0;
    00092
    00093     MM_PFN_LOCK_ASSERT();
    00094     CurrentProcess = PsGetCurrentProcess();
    00095
    00096     Va = StartingAddress;
    00097     PointerPpe = MiGetPpeAddress (Va);
    00098     PointerPde = MiGetPdeAddress (Va);
    00099     PointerPte = MiGetPteAddress (Va);
    00100     OriginalPointerPte = PointerPte;
    00101
    00102     do {
    00103
    00104         while (MiDoesPpeExistAndMakeValid (PointerPpe,
    00105                                            CurrentProcess,
    00106                                            TRUE,
    00107                                            &Waited)           ==  FALSE) {
    00108
    00109             //
    00110             // This page directory parent entry is empty, go to the next one.
    00111             //
    00112
    00113             PointerPpe += 1;
    00114             PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    00115             PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00116             Va = MiGetVirtualAddressMappedByPte (PointerPte);
    00117
    00118             if (Va > EndingAddress) {
    00119
    00120                 //
    00121                 // All done, return.
    00122                 //
    00123
    00124                 return;
    00125             }
    00126         }
    00127
    00128         Waited = 0;
    00129
    00130         while (MiDoesPdeExistAndMakeValid (PointerPde,
    00131                                            CurrentProcess,
    00132                                            TRUE,
    00133                                            &Waited)           ==  FALSE) {
    00134
    00135             //
    00136             // This page directory entry is empty, go to the next one.
    00137             //
    00138
    00139             PointerPde += 1;
    00140             PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00141             Va = MiGetVirtualAddressMappedByPte (PointerPte);
    00142
    00143             if (Va > EndingAddress) {
    00144
    00145                 //
    00146                 // All done, return.
    00147                 //
    00148
    00149                 return;
    00150             }
    00151 #if defined (_WIN64)
    00152             if (MiIsPteOnPdeBoundary (PointerPde)) {
    00153                 PointerPpe = MiGetPteAddress (PointerPde);
    00154                 Waited = 1;
    00155                 break;
    00156             }
    00157 #endif
    00158         }
    00159
    00160     } while (Waited != 0);
    00161
    00162     FirstValidVa = Va;
    00163     UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va);
    00164
    00165     //
    00166     // A valid PDE has been located, examine each PTE and delete them.
    00167     //
    00168
    00169     if ((Vad == (PMMVAD)NULL) ||
    00170         (Vad->u.VadFlags.PrivateMemory) ||
    00171         (Vad->FirstPrototypePte == (PMMPTE)NULL)) {
    00172         ProtoPte = (PMMPTE)NULL;
    00173         LastProtoPte = (PMMPTE)NULL;
    00174     } else {
    00175         ProtoPte = Vad->FirstPrototypePte;
    00176         LastProtoPte = (PMMPTE)4;
    00177     }
    00178
    00179     //
    00180     // Examine each PTE within the address range and delete it.
    00181     //
    00182
    00183     while (Va <= EndingAddress) {
    00184
    00185         //
    00186         // Note that the initial address could be aligned on a PPE or PDE
    00187         // boundary so we must check for it here.
    00188         //
    00189
    00190         if (MiIsVirtualAddressOnPdeBoundary(Va)) {
    00191
    00192             //
    00193             // The virtual address is on a page directory boundary,
    00194             // check the next PDE for validity and flush PTEs for the
    00195             // previous page table page.
    00196             //
    00197
    00198             MiFlushPteList (&FlushList, FALSE, ZeroPte);
    00199
    00200             //
    00201             // If all the entries have been eliminated from the previous
    00202             // page table page, delete the page table page itself.
    00203             //
    00204
    00205             if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) &&
    00206                 (PointerPde->u.Long != 0)) {
    00207
    00208                 TempVa = MiGetVirtualAddressMappedByPte(PointerPde);
    00209                 MiDeletePte (PointerPde,
    00210                              TempVa,
    00211                              AddressSpaceDeletion,
    00212                              CurrentProcess,
    00213                              NULL,
    00214                              NULL);
    00215
    00216 #if defined (_WIN64)
    00217                 if (Va == FirstValidVa) {
    00218                     UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
    00219                 }
    00220                 else {
    00221                     UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1);
    00222                 }
    00223
    00224                 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
    00225 #endif
    00226
    00227             }
    00228
    00229             if (MiIsVirtualAddressOnPpeBoundary(Va)) {
    00230
    00231                 if (Va == FirstValidVa) {
    00232                     UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
    00233                 }
    00234                 else {
    00235                     UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1);
    00236                 }
    00237
    00238                 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) &&
    00239                     (PointerPpe->u.Long != 0)) {
    00240
    00241                         TempVa = MiGetVirtualAddressMappedByPte(PointerPpe);
    00242                         MiDeletePte (PointerPpe,
    00243                                      TempVa,
    00244                                      AddressSpaceDeletion,
    00245                                      CurrentProcess,
    00246                                      NULL,
    00247                                      NULL);
    00248                 }
    00249             }
    00250
    00251             //
    00252             // Release the PFN lock.  This prevents a single thread
    00253             // from forcing other high priority threads from being
    00254             // blocked while a large address range is deleted.  There
    00255             // is nothing magic about the instructions within the
    00256             // lock and unlock.
    00257             //
    00258
    00259             UNLOCK_PFN (OldIrql);
    00260             PointerPde = MiGetPdeAddress (Va);
    00261             PointerPpe = MiGetPpeAddress (Va);
    00262             Skipped = FALSE;
    00263             LOCK_PFN (OldIrql);
    00264
    00265             do {
    00266                 while (MiDoesPpeExistAndMakeValid (PointerPpe,
    00267                                                    CurrentProcess,
    00268                                                    TRUE,
    00269                                                    &Waited)       ==  FALSE) {
    00270
    00271                     //
    00272                     // This page directory parent entry is empty,
    00273                     // go to the next one.
    00274                     //
    00275
    00276                     Skipped = TRUE;
    00277                     PointerPpe += 1;
    00278                     PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    00279                     PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00280                     Va = MiGetVirtualAddressMappedByPte (PointerPte);
    00281
    00282                     if (Va > EndingAddress) {
    00283
    00284                         //
    00285                         // All done, return.
    00286                         //
    00287
    00288                         return;
    00289                     }
    00290                 }
    00291
    00292                 Waited = 0;
    00293
    00294                 while (MiDoesPdeExistAndMakeValid (PointerPde,
    00295                                                    CurrentProcess,
    00296                                                    TRUE,
    00297                                                    &Waited)       ==  FALSE) {
    00298
    00299                     //
    00300                     // This page directory entry is empty, go to the next one.
    00301                     //
    00302
    00303                     Skipped = TRUE;
    00304                     PointerPde += 1;
    00305                     PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00306                     Va = MiGetVirtualAddressMappedByPte (PointerPte);
    00307
    00308                     if (Va > EndingAddress) {
    00309
    00310                         //
    00311                         // All done, remove any straggling page directories and
    00312                         // return.
    00313                         //
    00314
    00315 #if defined (_WIN64)
    00316
    00317                         PointerPde -= 1;
    00318                         PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00319                         UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
    00320
    00321                         if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) &&
    00322                             (PointerPpe->u.Long != 0)) {
    00323
    00324                                 TempVa = MiGetVirtualAddressMappedByPte(PointerPpe);
    00325                                 MiDeletePte (PointerPpe,
    00326                                              TempVa,
    00327                                              AddressSpaceDeletion,
    00328                                              CurrentProcess,
    00329                                              NULL,
    00330                                              NULL);
    00331                         }
    00332 #endif
    00333
    00334                         return;
    00335                     }
    00336
    00337 #if defined (_WIN64)
    00338                     if (MiIsPteOnPdeBoundary (PointerPde)) {
    00339                         PointerPpe = MiGetPteAddress (PointerPde);
    00340                         Waited = 1;
    00341                         break;
    00342                     }
    00343 #endif
    00344
    00345 #if DBG
    00346                     if ((LastProtoPte != NULL)  &&
    00347                         (Vad->u2.VadFlags2.ExtendableFile == 0)) {
    00348                         ProtoPte2 = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN (Va));
    00349                         Subsection = MiLocateSubsection (Vad,MI_VA_TO_VPN (Va));
    00350                         LastProtoPte2 = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
    00351                         if (Vad->u.VadFlags.ImageMap != 1) {
    00352                             if ((ProtoPte2 < Subsection->SubsectionBase) ||
    00353                                 (ProtoPte2 >= LastProtoPte2)) {
    00354                                 DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n",
    00355                                     ProtoPte2,Va,Vad,Subsection);
    00356                                 DbgBreakPoint();
    00357                             }
    00358                         }
    00359                     }
    00360 #endif //DBG
    00361                 }
    00362
    00363             } while (Waited != 0);
    00364
    00365             //
    00366             // The PPE and PDE are now valid, get the page table use count.
    00367             //
    00368
    00369             UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va);
    00370
    00371             //
    00372             // If we skipped chunks of address space, the prototype PTE pointer
    00373             // must be updated now so VADs that span multiple subsections
    00374             // are handled properly.
    00375             //
    00376
    00377             if ((Skipped == TRUE) && (LastProtoPte != NULL)) {
    00378
    00379                 ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va));
    00380                 Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va));
    00381
    00382                 if (Subsection != NULL) {
    00383                     LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
    00384 #if DBG
    00385                     if (Vad->u.VadFlags.ImageMap != 1) {
    00386                         if ((ProtoPte < Subsection->SubsectionBase) ||
    00387                             (ProtoPte >= LastProtoPte)) {
    00388                             DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n",
    00389                                         ProtoPte,Va,Vad,Subsection);
    00390                             DbgBreakPoint();
    00391                         }
    00392                     }
    00393 #endif //DBG
    00394                 }
    00395                 else {
    00396
    00397                     //
    00398                     // The Vad span is larger than the section being mapped.
    00399                     // Null the proto PTE local as no more proto PTEs will
    00400                     // need to be deleted at this point.
    00401                     //
    00402
    00403                     LastProtoPte = (PMMPTE)NULL;
    00404                 }
    00405             }
    00406         }
    00407
    00408         //
    00409         // The PPE and PDE are now valid, delete the PTEs.
    00410         //
    00411
    00412         if (PointerPte->u.Long != 0) {
    00413
    00414             //
    00415             // One less used page table entry in this page table page.
    00416             //
    00417
    00418             MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
    00419
    00420             if (IS_PTE_NOT_DEMAND_ZERO (*PointerPte)) {
    00421
    00422                 if (LastProtoPte != NULL) {
    00423                     if (ProtoPte >= LastProtoPte) {
    00424                         ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va));
    00425                         Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va));
    00426                         LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
    00427                     }
    00428 #if DBG
    00429                     if (Vad->u.VadFlags.ImageMap != 1) {
    00430                         if ((ProtoPte < Subsection->SubsectionBase) ||
    00431                             (ProtoPte >= LastProtoPte)) {
    00432                             DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n",
    00433                                         ProtoPte,Va,Vad,Subsection);
    00434                             DbgBreakPoint();
    00435                         }
    00436                     }
    00437 #endif //DBG
    00438                 }
    00439
    00440                 MiDeletePte (PointerPte,
    00441                              (PVOID)Va,
    00442                              AddressSpaceDeletion,
    00443                              CurrentProcess,
    00444                              ProtoPte,
    00445                              &FlushList);
    00446             } else {
    00447                 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
    00448             }
    00449         }
    00450
    00451         Va += PAGE_SIZE;
    00452         PointerPte += 1;
    00453         ProtoPte += 1;
    00454     }
    00455
    00456     //
    00457     // Flush out entries for the last page table page.
    00458     //
    00459
    00460     MiFlushPteList (&FlushList, FALSE, ZeroPte);
    00461
    00462     //
    00463     // If all the entries have been eliminated from the previous
    00464     // page table page, delete the page table page itself.
    00465     //
    00466
    00467     if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) &&
    00468         (PointerPde->u.Long != 0)) {
    00469
    00470         TempVa = MiGetVirtualAddressMappedByPte(PointerPde);
    00471         MiDeletePte (PointerPde,
    00472                      TempVa,
    00473                      AddressSpaceDeletion,
    00474                      CurrentProcess,
    00475                      NULL,
    00476                      NULL);
    00477
    00478 #if defined (_WIN64)
    00479         UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1);
    00480
    00481         MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
    00482
    00483         if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) &&
    00484             (PointerPpe->u.Long != 0)) {
    00485
    00486             TempVa = MiGetVirtualAddressMappedByPte(PointerPpe);
    00487             MiDeletePte (PointerPpe,
    00488                          TempVa,
    00489                          AddressSpaceDeletion,
    00490                          CurrentProcess,
    00491                          NULL,
    00492                          NULL);
    00493         }
    00494 #endif
    00495     }
    00496
    00497     //
    00498     // All done, return.
    00499     //
    00500
    00501     return;
    00502 }

VOID MiFlushPteList | ( | IN PMMPTE_FLUSH_LIST | PteFlushList,
|  | IN ULONG | AllProcessors,
|  | IN MMPTE | FillPte
| ) |

Definition at line 1160 of file deleteva.c.

References ASSERT, FALSE, KeFlushEntireTb(), KeFlushMultipleTb(), KeFlushSingleTb(), MiLockSystemSpaceAtDpcLevel, MiUnlockSystemSpaceFromDpcLevel, MM_FLUSH_COUNTER_MASK, MM_MAXIMUM_FLUSH_COUNT, MM_PFN_LOCK_ASSERT, MmFlushCounter, and TRUE.

Referenced by MiDeletePte(), MiDeleteSystemPagableVm(), MiDeleteVirtualAddresses(), MiProcessValidPteList(), MiReleaseSystemPtes(), MiRemoveMappedPtes(), MiRemoveWorkingSetPages(), MiReserveSystemPtes2(), and MmCleanProcessAddressSpace().

    01168                    :
    01169
    01170     This routine flushes all the PTEs in the PTE flush list.
    01171     If the list has overflowed, the entire TB is flushed.
    01172
    01173 Arguments:
    01174
    01175     PteFlushList - Supplies an optional pointer to the list to be flushed.
    01176
    01177     AllProcessors - Supplies TRUE if the flush occurs on all processors.
    01178
    01179     FillPte - Supplies the PTE to fill with.
    01180
    01181 Return Value:
    01182
    01183     None.
    01184
    01185 Environment:
    01186
    01187     Kernel mode, PFN lock held.
    01188
    01189 --*/
    01190
    01191 {
    01192     ULONG count;
    01193
    01194     ASSERT (ARGUMENT_PRESENT (PteFlushList));
    01195     MM_PFN_LOCK_ASSERT ();
    01196
    01197     count = PteFlushList->Count;
    01198
    01199     if (count != 0) {
    01200         if (count != 1) {
    01201             if (count < MM_MAXIMUM_FLUSH_COUNT) {
    01202                 KeFlushMultipleTb (count,
    01203                                    &PteFlushList->FlushVa[0],
    01204                                    TRUE,
    01205                                    (BOOLEAN)AllProcessors,
    01206                                    &((PHARDWARE_PTE)PteFlushList->FlushPte[0]),
    01207                                    FillPte.u.Flush);
    01208             } else {
    01209
    01210                 //
    01211                 // Array has overflowed, flush the entire TB.
    01212                 //
    01213
    01214                 if (AllProcessors == TRUE) {
    01215                     MiLockSystemSpaceAtDpcLevel();
    01216                     KeFlushEntireTb (TRUE, TRUE);
    01217                     MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK;
    01218                     MiUnlockSystemSpaceFromDpcLevel();
    01219                 } else {
    01220                     KeFlushEntireTb (TRUE, FALSE);
    01221                 }
    01222             }
    01223         } else {
    01224             KeFlushSingleTb (PteFlushList->FlushVa[0],
    01225                              TRUE,
    01226                              (BOOLEAN)AllProcessors,
    01227                              (PHARDWARE_PTE)PteFlushList->FlushPte[0],
    01228                              FillPte.u.Flush);
    01229         }
    01230         PteFlushList->Count = 0;
    01231     }
    01232     return;
    01233 }
    }

ULONG FASTCALL MiReleasePageFileSpace | ( | IN MMPTE | PteContents | ) |

Definition at line 1014 of file deleteva.c.

References ASSERT, _MMPAGING_FILE::CurrentUsage, FALSE, _MMPAGING_FILE::FreeSpace, GET_PAGING_FILE_NUMBER, GET_PAGING_FILE_OFFSET, MiUpdateModifiedWriterMdls(), MM_PFN_LOCK_ASSERT, MM_USABLE_PAGES_FREE, MmNumberOfActiveMdlEntries, MmPagingFile, MmPagingFileDebug, RtlClearBits(), and TRUE.

Referenced by MiCleanSection(), MiCompleteProtoPteFault(), MiCopyOnWrite(), MiDecommitPages(), MiDecrementCloneBlockReference(), MiDecrementReferenceCount(), MiDeletePte(), MiDeleteSystemPagableVm(), MiMakeOutswappedPageResident(), MiPurgeImageSection(), MiResetVirtualMemory(), MiSegmentDelete(), MiSetDirtyBit(), MiSetModifyBit(), MiSetPageModified(), MiWriteComplete(), MmPurgeSection(), MmSetAddressRangeModified(), and MmUnlockPages().

    01020                    :
    01021
    01022     This routine frees the paging file allocated to the specified PTE
    01023     and adjusts the necessary quotas.
    01024
    01025 Arguments:
    01026
    01027     PteContents - Supplies the PTE which is in page file format.
    01028
    01029 Return Value:
    01030
    01031     Returns TRUE if any paging file space was deallocated.
    01032
    01033 Environment:
    01034
    01035     Kernel mode, APCs disabled, PFN lock held.
    01036
    01037 --*/
    01038
    01039 {
    01040     ULONG FreeBit;
    01041     ULONG PageFileNumber;
    01042
    01043     MM_PFN_LOCK_ASSERT();
    01044
    01045     if (PteContents.u.Soft.Prototype == 1) {
    01046
    01047         //
    01048         // Not in page file format.
    01049         //
    01050
    01051         return FALSE;
    01052     }
    01053
    01054     FreeBit = GET_PAGING_FILE_OFFSET (PteContents);
    01055
    01056     if ((FreeBit == 0) || (FreeBit == 0xFFFFF)) {
    01057
    01058         //
    01059         // Page is not in a paging file, just return.
    01060         //
    01061
    01062         return FALSE;
    01063     }
    01064
    01065     PageFileNumber = GET_PAGING_FILE_NUMBER (PteContents);
    01066
    01067     ASSERT (RtlCheckBit( MmPagingFile[PageFileNumber]->Bitmap, FreeBit) == 1);
    01068
    01069 #if DBG
    01070     if ((FreeBit < 8192) && (PageFileNumber == 0)) {
    01071         ASSERT ((MmPagingFileDebug[FreeBit] & 1) != 0);
    01072         MmPagingFileDebug[FreeBit] ^= 1;
    01073     }
    01074 #endif //DBG
    01075
    01076     RtlClearBits ( MmPagingFile[PageFileNumber]->Bitmap, FreeBit, 1);
    01077
    01078     MmPagingFile[PageFileNumber]->FreeSpace += 1;
    01079     MmPagingFile[PageFileNumber]->CurrentUsage -= 1;
    01080
    01081     //
    01082     // Check to see if we should move some MDL entries for the
    01083     // modified page writer now that more free space is available.
    01084     //
    01085
    01086     if ((MmNumberOfActiveMdlEntries == 0) ||
    01087         (MmPagingFile[PageFileNumber]->FreeSpace == MM_USABLE_PAGES_FREE)) {
    01088
    01089         MiUpdateModifiedWriterMdls (PageFileNumber);
    01090     }
    01091
    01092     return TRUE;
    01093 }

VOID FASTCALL MiUpdateModifiedWriterMdls | ( | IN ULONG | PageFileNumber | ) |

Definition at line 1098 of file deleteva.c.

References _MMMOD_WRITER_MDL_ENTRY::CurrentList, _MMPAGING_FILE::Entry, _MMMOD_WRITER_LISTHEAD::Event, FALSE, KeSetEvent(), _MMMOD_WRITER_MDL_ENTRY::Links, _MMMOD_WRITER_LISTHEAD::ListHead, MM_IO_IN_PROGRESS, MM_PAGING_FILE_MDLS, MmFreePagingSpaceLow, MmNumberOfActiveMdlEntries, MmPagingFile, MmPagingFileHeader, _MMMOD_WRITER_MDL_ENTRY::PagingListHead, and PMMMOD_WRITER_MDL_ENTRY.

Referenced by MiAttemptPageFileExtension(), MiExtendPagingFileMaximum(), and MiReleasePageFileSpace().

    01104                    :
    01105
    01106     This routine ensures the MDLs for the specified paging file
    01107     are in the proper state such that paging i/o can continue.
    01108
    01109 Arguments:
    01110
    01111     PageFileNumber - Supplies the page file number to check the MDLs for.
    01112
    01113 Return Value:
    01114
    01115     None.
    01116
    01117 Environment:
    01118
    01119     Kernel mode, PFN lock held.
    01120
    01121 --*/
    01122
    01123 {
    01124     ULONG i;
    01125     PMMMOD_WRITER_MDL_ENTRY WriterEntry;
    01126
    01127     //
    01128     // Put the MDL entries into the active list.
    01129     //
    01130
    01131     for (i = 0; i < MM_PAGING_FILE_MDLS; i += 1) {
    01132
    01133         if ((MmPagingFile[PageFileNumber]->Entry[i]->Links.Flink !=
    01134                                                     MM_IO_IN_PROGRESS)
    01135                           &&
    01136             (MmPagingFile[PageFileNumber]->Entry[i]->CurrentList ==
    01137                     &MmFreePagingSpaceLow)) {
    01138
    01139             //
    01140             // Remove this entry and put it on the active list.
    01141             //
    01142
    01143             WriterEntry = MmPagingFile[PageFileNumber]->Entry[i];
    01144             RemoveEntryList (&WriterEntry->Links);
    01145             WriterEntry->CurrentList = &MmPagingFileHeader.ListHead;
    01146
    01147             KeSetEvent (&WriterEntry->PagingListHead->Event, 0, FALSE);
    01148
    01149             InsertTailList (&WriterEntry->PagingListHead->ListHead,
    01150                             &WriterEntry->Links);
    01151             MmNumberOfActiveMdlEntries += 1;
    01152         }
    01153     }
    01154
    01155     return;
    01156 }