ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

swapout.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00017  *
00018  *
00019  * PROJECT:         ReactOS kernel
00020  * FILE:            ntoskrnl/mm/section/fault.c
00021  * PURPOSE:         Consolidate fault handlers for sections
00022  *
00023  * PROGRAMMERS:     Arty
00024  *                  Rex Jolliff
00025  *                  David Welch
00026  *                  Eric Kohl
00027  *                  Emanuele Aliberti
00028  *                  Eugene Ingerman
00029  *                  Casper Hornstrup
00030  *                  KJK::Hyperion
00031  *                  Guido de Jong
00032  *                  Ge van Geldorp
00033  *                  Royce Mitchell III
00034  *                  Filip Navara
00035  *                  Aleksey Bragin
00036  *                  Jason Filby
00037  *                  Thomas Weidenmueller
00038  *                  Gunnar Andre' Dalsnes
00039  *                  Mike Nordell
00040  *                  Alex Ionescu
00041  *                  Gregor Anich
00042  *                  Steven Edwards
00043  *                  Herve Poussineau
00044  */
00045 
00046 /*
00047 
00048 This file implements page out infrastructure for cache type sections.  This
00049 is implemented a little differently from the legacy mm because mapping in an
00050 address space and membership in a segment are considered separate.
00051 
00052 The general strategy here is to try to remove all mappings as gently as
00053 possible, then to remove the page entry from the section itself as a final
00054 step.  If at any time during the page out operation, the page is mapped in
00055 a new address space by a competing thread, the operation will abort before
00056 the segment page is finally removed, and the page will be naturally faulted
00057 back into any address spaces required in the normal way.
00058 
00059 */
00060 
00061 /* INCLUDES *****************************************************************/
00062 
00063 #include <ntoskrnl.h>
00064 #include "newmm.h"
00065 #define NDEBUG
00066 #include <debug.h>
00067 
00068 #define DPRINTC DPRINT
00069 
00070 extern KEVENT MmWaitPageEvent;
00071 extern FAST_MUTEX RmapListLock;
00072 extern PMMWSL MmWorkingSetList;
00073 
00074 FAST_MUTEX MiGlobalPageOperation;
00075 
00076 /*
00077 
00078 MmWithdrawSectionPage removes a page entry from the section segment, replacing
00079 it with a wait entry.  The caller must replace the wait entry with a 0, when
00080 any required writing is done.  The wait entry must remain until the page is
00081 written to protect against cases where a fault brings a stale copy of the page
00082 back before writing is complete.
00083 
00084 */
00085 PFN_NUMBER
00086 NTAPI
00087 MmWithdrawSectionPage(PMM_SECTION_SEGMENT Segment,
00088                       PLARGE_INTEGER FileOffset,
00089                       BOOLEAN *Dirty)
00090 {
00091     ULONG_PTR Entry;
00092 
00093     DPRINT("MmWithdrawSectionPage(%x,%08x%08x,%x)\n",
00094            Segment,
00095            FileOffset->HighPart,
00096            FileOffset->LowPart,
00097            Dirty);
00098 
00099     MmLockSectionSegment(Segment);
00100     Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
00101 
00102     *Dirty = !!IS_DIRTY_SSE(Entry);
00103 
00104     DPRINT("Withdraw %x (%x) of %wZ\n",
00105            FileOffset->LowPart,
00106            Entry,
00107            Segment->FileObject ? &Segment->FileObject->FileName : NULL);
00108 
00109     if (!Entry)
00110     {
00111         DPRINT("Stoeled!\n");
00112         MmUnlockSectionSegment(Segment);
00113         return 0;
00114     }
00115     else if (MM_IS_WAIT_PTE(Entry))
00116     {
00117         DPRINT("WAIT\n");
00118         MmUnlockSectionSegment(Segment);
00119         return MM_WAIT_ENTRY;
00120     }
00121     else if (Entry && !IS_SWAP_FROM_SSE(Entry))
00122     {
00123         DPRINT("Page %x\n", PFN_FROM_SSE(Entry));
00124 
00125         *Dirty |= (Entry & 2);
00126 
00127         MmSetPageEntrySectionSegment(Segment,
00128                                      FileOffset,
00129                                      MAKE_SWAP_SSE(MM_WAIT_ENTRY));
00130 
00131         MmUnlockSectionSegment(Segment);
00132         return PFN_FROM_SSE(Entry);
00133     }
00134     else
00135     {
00136         DPRINT1("SWAP ENTRY?! (%x:%08x%08x)\n",
00137                 Segment,
00138                 FileOffset->HighPart,
00139                 FileOffset->LowPart);
00140 
00141         ASSERT(FALSE);
00142         MmUnlockSectionSegment(Segment);
00143         return 0;
00144     }
00145 }
00146 
00147 /*
00148 
00149 This function determines whether the segment holds the very last reference to
00150 the page being considered and if so, writes it back or discards it as
00151 approriate.  One small niggle here is that we might be holding the last
00152 reference to the section segment associated with this page.  That happens
00153 when the segment is destroyed at the same time that an active swap operation
00154 is occurring, and all maps were already withdrawn.  In that case, it's our
00155 responsiblity for finalizing the segment.
00156 
00157 Note that in the current code, WriteZero is always TRUE because the section
00158 always backs a file.  In the ultimate form of this code, it also writes back
00159 pages without necessarily evicting them.  In reactos' trunk, this is vestigal.
00160 
00161 */
00162 
00163 NTSTATUS
00164 NTAPI
00165 MmFinalizeSectionPageOut(PMM_SECTION_SEGMENT Segment,
00166                          PLARGE_INTEGER FileOffset,
00167                          PFN_NUMBER Page,
00168                          BOOLEAN Dirty)
00169 {
00170     NTSTATUS Status = STATUS_SUCCESS;
00171     BOOLEAN WriteZero = FALSE, WritePage = FALSE;
00172     SWAPENTRY Swap = MmGetSavedSwapEntryPage(Page);
00173 
00174     /* Bail early if the reference count isn't where we need it */
00175     if (MmGetReferenceCountPage(Page) != 1)
00176     {
00177         DPRINT1("Cannot page out locked page %x with ref count %d\n",
00178                 Page,
00179                 MmGetReferenceCountPage(Page));
00180         return STATUS_UNSUCCESSFUL;
00181     }
00182 
00183     MmLockSectionSegment(Segment);
00184     (void)InterlockedIncrementUL(&Segment->ReferenceCount);
00185 
00186     if (Dirty)
00187     {
00188         DPRINT("Finalize (dirty) Segment %x Page %x\n", Segment, Page);
00189         DPRINT("Segment->FileObject %x\n", Segment->FileObject);
00190         DPRINT("Segment->Flags %x\n", Segment->Flags);
00191 
00192         WriteZero = TRUE;
00193         WritePage = TRUE;
00194     }
00195     else
00196     {
00197         WriteZero = TRUE;
00198     }
00199 
00200     DPRINT("Status %x\n", Status);
00201 
00202     MmUnlockSectionSegment(Segment);
00203 
00204     if (WritePage)
00205     {
00206         DPRINT("MiWriteBackPage(Segment %x FileObject %x Offset %x)\n",
00207                Segment,
00208                Segment->FileObject,
00209                FileOffset->LowPart);
00210 
00211         Status = MiWriteBackPage(Segment->FileObject,
00212                                  FileOffset,
00213                                  PAGE_SIZE,
00214                                  Page);
00215     }
00216 
00217     MmLockSectionSegment(Segment);
00218 
00219     if (WriteZero && NT_SUCCESS(Status))
00220     {
00221         DPRINT("Setting page entry in segment %x:%x to swap %x\n",
00222                Segment,
00223                FileOffset->LowPart,
00224                Swap);
00225 
00226         MmSetPageEntrySectionSegment(Segment,
00227                                      FileOffset,
00228                                      Swap ? MAKE_SWAP_SSE(Swap) : 0);
00229     }
00230     else
00231     {
00232         DPRINT("Setting page entry in segment %x:%x to page %x\n",
00233                Segment,
00234                FileOffset->LowPart,
00235                Page);
00236 
00237         MmSetPageEntrySectionSegment(Segment,
00238                                      FileOffset,
00239                                      Page ? (Dirty ? DIRTY_SSE(MAKE_PFN_SSE(Page)) : MAKE_PFN_SSE(Page)) : 0);
00240     }
00241 
00242     if (NT_SUCCESS(Status))
00243     {
00244         DPRINT("Removing page %x for real\n", Page);
00245         MmSetSavedSwapEntryPage(Page, 0);
00246         MmReleasePageMemoryConsumer(MC_CACHE, Page);
00247     }
00248 
00249     MmUnlockSectionSegment(Segment);
00250 
00251     if (InterlockedDecrementUL(&Segment->ReferenceCount) == 0)
00252     {
00253         MmFinalizeSegment(Segment);
00254     }
00255 
00256     /* Note: Writing may evict the segment... Nothing is guaranteed from here down */
00257     MiSetPageEvent(Segment, FileOffset->LowPart);
00258 
00259     DPRINT("Status %x\n", Status);
00260     return Status;
00261 }
00262 
00263 /*
00264 
00265 The slightly misnamed MmPageOutCacheSection removes a page from an address
00266 space in the manner of fault handlers found in fault.c.  In the ultimate form
00267 of the code, this is one of the function pointers stored in a memory area
00268 to control how pages in that memory area are managed.
00269 
00270 Also misleading is the call to MmReleasePageMemoryConsumer, which releases
00271 the reference held by this address space only.  After all address spaces
00272 have had MmPageOutCacheSection succeed on them for the indicated page,
00273 then paging out of a cache page can continue.
00274 
00275 */
00276 
00277 NTSTATUS
00278 NTAPI
00279 MmPageOutCacheSection(PMMSUPPORT AddressSpace,
00280                       MEMORY_AREA* MemoryArea,
00281                       PVOID Address,
00282                       PBOOLEAN Dirty,
00283                       PMM_REQUIRED_RESOURCES Required)
00284 {
00285     ULONG_PTR Entry;
00286     PFN_NUMBER OurPage;
00287     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
00288     LARGE_INTEGER TotalOffset;
00289     PMM_SECTION_SEGMENT Segment;
00290     PVOID PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
00291 
00292     TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
00293                            MemoryArea->Data.SectionData.ViewOffset.QuadPart;
00294 
00295     Segment = MemoryArea->Data.SectionData.Segment;
00296 
00297     MmLockSectionSegment(Segment);
00298     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
00299 
00300     Entry = MmGetPageEntrySectionSegment(Segment, &TotalOffset);
00301 
00302     if (MmIsPageSwapEntry(Process, PAddress))
00303     {
00304         SWAPENTRY SwapEntry;
00305         MmGetPageFileMapping(Process, PAddress, &SwapEntry);
00306         MmUnlockSectionSegment(Segment);
00307         return SwapEntry == MM_WAIT_ENTRY ? STATUS_SUCCESS + 1 : STATUS_UNSUCCESSFUL;
00308     }
00309 
00310     MmDeleteRmap(Required->Page[0], Process, Address);
00311     MmDeleteVirtualMapping(Process, Address, FALSE, Dirty, &OurPage);
00312     ASSERT(OurPage == Required->Page[0]);
00313 
00314     /* Note: this releases the reference held by this address space only. */
00315     MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]);
00316 
00317     MmUnlockSectionSegment(Segment);
00318     MiSetPageEvent(Process, Address);
00319     return STATUS_SUCCESS;
00320 }
00321 
00322 /*
00323 
00324 This function is called by rmap when spare pages are needed by the blancer.
00325 It attempts first to release the page from every address space in which it
00326 appears, and, after a final check that no competing thread has mapped the
00327 page again, uses MmFinalizeSectionPageOut to completely evict the page.  If
00328 that's successful, then a suitable non-page map will be left in the segment
00329 page table, otherwise, the original page is replaced in the section page
00330 map.  Failure may result from a variety of conditions, but always leaves
00331 the page mapped.
00332 
00333 This code is like the other fault handlers, in that MmPageOutCacheSection has
00334 the option of returning either STATUS_SUCCESS + 1 to wait for a wait entry
00335 to disppear or to use the blocking callout facility by returning
00336 STATUS_MORE_PROCESSING_REQUIRED and placing a pointer to a function from
00337 reqtools.c in the MM_REQUIRED_RESOURCES struct.
00338 
00339 */
00340 
00341 NTSTATUS
00342 NTAPI
00343 MmpPageOutPhysicalAddress(PFN_NUMBER Page)
00344 {
00345     BOOLEAN ProcRef = FALSE, PageDirty;
00346     PFN_NUMBER SectionPage = 0;
00347     PMM_RMAP_ENTRY entry;
00348     PMM_SECTION_SEGMENT Segment = NULL;
00349     LARGE_INTEGER FileOffset;
00350     PMEMORY_AREA MemoryArea;
00351     PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
00352     BOOLEAN Dirty = FALSE;
00353     PVOID Address = NULL;
00354     PEPROCESS Process = NULL;
00355     NTSTATUS Status = STATUS_SUCCESS;
00356     MM_REQUIRED_RESOURCES Resources = { 0 };
00357 
00358     DPRINTC("Page out %x (ref ct %x)\n", Page, MmGetReferenceCountPage(Page));
00359 
00360     ExAcquireFastMutex(&MiGlobalPageOperation);
00361     if ((Segment = MmGetSectionAssociation(Page, &FileOffset)))
00362     {
00363         DPRINTC("Withdrawing page (%x) %x:%x\n",
00364                 Page,
00365                 Segment,
00366                 FileOffset.LowPart);
00367 
00368         SectionPage = MmWithdrawSectionPage(Segment, &FileOffset, &Dirty);
00369         DPRINTC("SectionPage %x\n", SectionPage);
00370 
00371         if (SectionPage == MM_WAIT_ENTRY || SectionPage == 0)
00372         {
00373             DPRINT1("In progress page out %x\n", SectionPage);
00374             ExReleaseFastMutex(&MiGlobalPageOperation);
00375             return STATUS_UNSUCCESSFUL;
00376         }
00377         else
00378         {
00379             ASSERT(SectionPage == Page);
00380         }
00381         Resources.State = Dirty ? 1 : 0;
00382     }
00383     else
00384     {
00385         DPRINT("No segment association for %x\n", Page);
00386     }
00387 
00388 
00389     Dirty = MmIsDirtyPageRmap(Page);
00390 
00391     DPRINTC("Trying to unmap all instances of %x\n", Page);
00392     ExAcquireFastMutex(&RmapListLock);
00393     entry = MmGetRmapListHeadPage(Page);
00394 
00395     // Entry and Segment might be null here in the case that the page
00396     // is new and is in the process of being swapped in
00397     if (!entry && !Segment)
00398     {
00399         Status = STATUS_UNSUCCESSFUL;
00400         DPRINT1("Page %x is in transit\n", Page);
00401         ExReleaseFastMutex(&RmapListLock);
00402         goto bail;
00403     }
00404 
00405     while (entry != NULL && NT_SUCCESS(Status))
00406     {
00407         Process = entry->Process;
00408         Address = entry->Address;
00409 
00410         DPRINTC("Process %x Address %x Page %x\n", Process, Address, Page);
00411 
00412         if (RMAP_IS_SEGMENT(Address)) {
00413             entry = entry->Next;
00414             continue;
00415         }
00416 
00417         if (Process && Address < MmSystemRangeStart)
00418         {
00419             /* Make sure we don't try to page out part of an exiting process */
00420             if (PspIsProcessExiting(Process))
00421             {
00422                 DPRINT("bail\n");
00423                 ExReleaseFastMutex(&RmapListLock);
00424                 goto bail;
00425             }
00426             ObReferenceObject(Process);
00427             ProcRef = TRUE;
00428             AddressSpace = &Process->Vm;
00429         }
00430         else
00431         {
00432             AddressSpace = MmGetKernelAddressSpace();
00433         }
00434         ExReleaseFastMutex(&RmapListLock);
00435 
00436         RtlZeroMemory(&Resources, sizeof(Resources));
00437 
00438         if ((((ULONG_PTR)Address) & 0xFFF) != 0)
00439         {
00440             KeBugCheck(MEMORY_MANAGEMENT);
00441         }
00442 
00443         MmLockAddressSpace(AddressSpace);
00444 
00445         do
00446         {
00447             MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
00448             if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
00449             {
00450                 Status = STATUS_UNSUCCESSFUL;
00451                 MmUnlockAddressSpace(AddressSpace);
00452                 DPRINTC("bail\n");
00453                 goto bail;
00454             }
00455 
00456             DPRINTC("Type %x (%x -> %x)\n",
00457                     MemoryArea->Type,
00458                     MemoryArea->StartingAddress,
00459                     MemoryArea->EndingAddress);
00460 
00461             Resources.DoAcquisition = NULL;
00462             Resources.Page[0] = Page;
00463 
00464             ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
00465 
00466             DPRINT("%x:%x, page %x %x\n",
00467                    Process,
00468                    Address,
00469                    Page,
00470                    Resources.Page[0]);
00471 
00472             PageDirty = FALSE;
00473 
00474             Status = MmPageOutCacheSection(AddressSpace,
00475                                            MemoryArea,
00476                                            Address,
00477                                            &PageDirty,
00478                                            &Resources);
00479 
00480             Dirty |= PageDirty;
00481             DPRINT("%x\n", Status);
00482 
00483             ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
00484 
00485             MmUnlockAddressSpace(AddressSpace);
00486 
00487             if (Status == STATUS_SUCCESS + 1)
00488             {
00489                 // Wait page ... the other guy has it, so we'll just fail for now
00490                 DPRINT1("Wait entry ... can't continue\n");
00491                 Status = STATUS_UNSUCCESSFUL;
00492                 goto bail;
00493             }
00494             else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
00495             {
00496                 DPRINTC("DoAcquisition %x\n", Resources.DoAcquisition);
00497 
00498                 Status = Resources.DoAcquisition(AddressSpace,
00499                                                  MemoryArea,
00500                                                  &Resources);
00501 
00502                 DPRINTC("Status %x\n", Status);
00503                 if (!NT_SUCCESS(Status))
00504                 {
00505                     DPRINT1("bail\n");
00506                     goto bail;
00507                 }
00508                 else Status = STATUS_MM_RESTART_OPERATION;
00509             }
00510 
00511             MmLockAddressSpace(AddressSpace);
00512         }
00513         while (Status == STATUS_MM_RESTART_OPERATION);
00514 
00515         MmUnlockAddressSpace(AddressSpace);
00516 
00517         if (ProcRef)
00518         {
00519             ObDereferenceObject(Process);
00520             ProcRef = FALSE;
00521         }
00522 
00523         ExAcquireFastMutex(&RmapListLock);
00524         ASSERT(!MM_IS_WAIT_PTE(MmGetPfnForProcess(Process, Address)));
00525         entry = MmGetRmapListHeadPage(Page);
00526 
00527         DPRINTC("Entry %x\n", entry);
00528     }
00529 
00530     ExReleaseFastMutex(&RmapListLock);
00531 
00532 bail:
00533     DPRINTC("BAIL %x\n", Status);
00534 
00535     if (Segment)
00536     {
00537         ULONG RefCount;
00538 
00539         DPRINTC("About to finalize section page %x (%x:%x) Status %x %s\n",
00540                 Page,
00541                 Segment,
00542                 FileOffset.LowPart,
00543                 Status,
00544                 Dirty ? "dirty" : "clean");
00545 
00546         if (!NT_SUCCESS(Status) ||
00547             !NT_SUCCESS(Status = MmFinalizeSectionPageOut(Segment,
00548                                                           &FileOffset,
00549                                                           Page,
00550                                                           Dirty)))
00551         {
00552             DPRINTC("Failed to page out %x, replacing %x at %x in segment %x\n",
00553                     SectionPage,
00554                     FileOffset.LowPart,
00555                     Segment);
00556 
00557             MmLockSectionSegment(Segment);
00558 
00559             MmSetPageEntrySectionSegment(Segment,
00560                                          &FileOffset,
00561                                          Dirty ? MAKE_PFN_SSE(Page) : DIRTY_SSE(MAKE_PFN_SSE(Page)));
00562 
00563             MmUnlockSectionSegment(Segment);
00564         }
00565 
00566         /* Alas, we had the last reference */
00567         if ((RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
00568             MmFinalizeSegment(Segment);
00569     }
00570 
00571     if (ProcRef)
00572     {
00573         DPRINTC("Dereferencing process...\n");
00574         ObDereferenceObject(Process);
00575     }
00576 
00577     ExReleaseFastMutex(&MiGlobalPageOperation);
00578 
00579     DPRINTC("%s %x %x\n",
00580             NT_SUCCESS(Status) ? "Evicted" : "Spared",
00581             Page,
00582             Status);
00583 
00584     return NT_SUCCESS(Status) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
00585 }
00586 
00587 ULONG
00588 NTAPI
00589 MiCacheEvictPages(PMM_SECTION_SEGMENT Segment,
00590                   ULONG Target)
00591 {
00592     ULONG_PTR Entry;
00593     ULONG Result = 0, i, j;
00594     NTSTATUS Status;
00595     PFN_NUMBER Page;
00596     LARGE_INTEGER Offset;
00597 
00598     MmLockSectionSegment(Segment);
00599 
00600     for (i = 0; i < RtlNumberGenericTableElements(&Segment->PageTable); i++) {
00601 
00602         PCACHE_SECTION_PAGE_TABLE Element = RtlGetElementGenericTable(&Segment->PageTable,
00603                                                                       i);
00604 
00605         ASSERT(Element);
00606 
00607         Offset = Element->FileOffset;
00608         for (j = 0; j < ENTRIES_PER_ELEMENT; j++, Offset.QuadPart += PAGE_SIZE) {
00609             Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
00610             if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
00611                 Page = PFN_FROM_SSE(Entry);
00612                 MmUnlockSectionSegment(Segment);
00613                 Status = MmpPageOutPhysicalAddress(Page);
00614                 if (NT_SUCCESS(Status))
00615                     Result++;
00616                 MmLockSectionSegment(Segment);
00617             }
00618         }
00619     }
00620 
00621     MmUnlockSectionSegment(Segment);
00622 
00623     return Result;
00624 }
00625 
00626 extern LIST_ENTRY MiSegmentList;
00627 
00628 // Interact with legacy balance manager for now
00629 // This can fall away when our section implementation supports
00630 // demand paging properly
00631 NTSTATUS
00632 MiRosTrimCache(ULONG Target,
00633                ULONG Priority,
00634                PULONG NrFreed)
00635 {
00636     ULONG Freed;
00637     PLIST_ENTRY Entry;
00638     PMM_SECTION_SEGMENT Segment;
00639     *NrFreed = 0;
00640 
00641     DPRINT1("Need to trim %d cache pages\n", Target);
00642     for (Entry = MiSegmentList.Flink;
00643          *NrFreed < Target && Entry != &MiSegmentList;
00644          Entry = Entry->Flink) {
00645         Segment = CONTAINING_RECORD(Entry, MM_SECTION_SEGMENT, ListOfSegments);
00646         /* Defer to MM to try recovering pages from it */
00647         Freed = MiCacheEvictPages(Segment, Target);
00648         *NrFreed += Freed;
00649     }
00650     DPRINT1("Evicted %d cache pages\n", Target);
00651 
00652     if (!IsListEmpty(&MiSegmentList)) {
00653         Entry = MiSegmentList.Flink;
00654         RemoveEntryList(Entry);
00655         InsertTailList(&MiSegmentList, Entry);
00656     }
00657 
00658     return STATUS_SUCCESS;
00659 }

Generated on Sun May 27 2012 04:37:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.