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

data.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.c
00021  * PURPOSE:         Implements section objects
00022  *
00023  * PROGRAMMERS:     Rex Jolliff
00024  *                  David Welch
00025  *                  Eric Kohl
00026  *                  Emanuele Aliberti
00027  *                  Eugene Ingerman
00028  *                  Casper Hornstrup
00029  *                  KJK::Hyperion
00030  *                  Guido de Jong
00031  *                  Ge van Geldorp
00032  *                  Royce Mitchell III
00033  *                  Filip Navara
00034  *                  Aleksey Bragin
00035  *                  Jason Filby
00036  *                  Thomas Weidenmueller
00037  *                  Gunnar Andre' Dalsnes
00038  *                  Mike Nordell
00039  *                  Alex Ionescu
00040  *                  Gregor Anich
00041  *                  Steven Edwards
00042  *                  Herve Poussineau
00043  */
00044 
00045 /*
00046 
00047 A note on this code:
00048 
00049 Unlike the previous section code, this code does not rely on an active map
00050 for a page to exist in a data segment.  Each mapping contains a large integer
00051 offset to map at, and the segment always represents the entire section space
00052 from zero to the maximum long long.  This allows us to associate one single
00053 page map with each file object, and to let each mapping view an offset into
00054 the overall mapped file.  Temporarily unmapping the file has no effect on the
00055 section membership.
00056 
00057 This necessitates a change in the section page table implementation, which is
00058 now an RtlGenericTable.  This will be elaborated more in sptab.c.  One upshot
00059 of this change is that a mapping of a small files takes a bit more than 1/4
00060 of the size in nonpaged kernel space as it did previously.
00061 
00062 When we need other threads that may be competing for the same page fault to
00063 wait, we have a mechanism seperate from PageOps for dealing with that, which
00064 was suggested by Travis Geiselbrecht after a conversation I had with Alex
00065 Ionescu.  That mechanism is the MM_WAIT_ENTRY, which is the all-ones SWAPENTRY.
00066 
00067 When we wish for other threads to know that we're waiting and will finish
00068 handling a page fault, we place the swap entry MM_WAIT_ENTRY in the page table
00069 at the fault address (this works on either the section page table or a process
00070 address space), perform any blocking operations required, then replace the
00071 entry.
00072 
00073 */
00074 
00075 /* INCLUDES *****************************************************************/
00076 
00077 #include <ntoskrnl.h>
00078 #include "newmm.h"
00079 #include "../newcc.h"
00080 #define NDEBUG
00081 #include <debug.h>
00082 #include "../mm/ARM3/miarm.h"
00083 
00084 #define DPRINTC DPRINT
00085 
00086 LIST_ENTRY MiSegmentList;
00087 
00088 extern KEVENT MpwThreadEvent;
00089 extern KSPIN_LOCK MiSectionPageTableLock;
00090 extern PMMWSL MmWorkingSetList;
00091 
00092 /* GLOBALS *******************************************************************/
00093 
00094 ULONG_PTR MmSubsectionBase;
00095 
00096 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
00097 {
00098     ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
00099     ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
00100 };
00101 
00102 /* FUNCTIONS *****************************************************************/
00103 
00104 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
00105 
00106 VOID
00107 NTAPI
00108 _MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
00109 {
00110     //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
00111     ExAcquireFastMutex(&Segment->Lock);
00112     Segment->Locked = TRUE;
00113 }
00114 
00115 VOID
00116 NTAPI
00117 _MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
00118 {
00119     ASSERT(Segment->Locked);
00120     Segment->Locked = FALSE;
00121     ExReleaseFastMutex(&Segment->Lock);
00122     //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
00123 }
00124 
00125 NTSTATUS
00126 NTAPI
00127 MiZeroFillSection(PVOID Address, PLARGE_INTEGER FileOffsetPtr, ULONG Length)
00128 {
00129     PFN_NUMBER Page;
00130     PMMSUPPORT AddressSpace;
00131     PMEMORY_AREA MemoryArea;
00132     PMM_SECTION_SEGMENT Segment;
00133     LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
00134     KIRQL OldIrql;
00135 
00136     DPRINT("MiZeroFillSection(Address %x,Offset %x,Length %x)\n",
00137            Address,
00138            FileOffset.LowPart,
00139            Length);
00140 
00141     AddressSpace = MmGetKernelAddressSpace();
00142 
00143     MmLockAddressSpace(AddressSpace);
00144     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
00145     MmUnlockAddressSpace(AddressSpace);
00146     if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW || MemoryArea->DeleteInProgress)
00147     {
00148         return STATUS_NOT_MAPPED_DATA;
00149     }
00150 
00151     Segment = MemoryArea->Data.SectionData.Segment;
00152     End.QuadPart = FileOffset.QuadPart + Length;
00153     End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
00154     FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
00155     FirstMapped.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
00156     DPRINT("Pulling zero pages for %08x%08x-%08x%08x\n",
00157            FileOffset.u.HighPart, FileOffset.u.LowPart,
00158            End.u.HighPart, End.u.LowPart);
00159     while (FileOffset.QuadPart < End.QuadPart)
00160     {
00161         PVOID Address;
00162         ULONG_PTR Entry;
00163 
00164         if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
00165             break;
00166 
00167         MmLockAddressSpace(AddressSpace);
00168         MmLockSectionSegment(Segment);
00169 
00170         Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
00171         if (Entry == 0)
00172         {
00173             MmSetPageEntrySectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
00174             Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
00175 
00176             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00177             MmReferencePage(Page);
00178             KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00179 
00180             MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1);
00181             MmInsertRmap(Page, NULL, Address);
00182         }
00183         else
00184         {
00185             MmReleasePageMemoryConsumer(MC_CACHE, Page);
00186         }
00187 
00188         MmUnlockSectionSegment(Segment);
00189         MmUnlockAddressSpace(AddressSpace);
00190 
00191         FileOffset.QuadPart += PAGE_SIZE;
00192     }
00193     return STATUS_SUCCESS;
00194 }
00195 
00196 /*
00197 
00198 MiFlushMappedSection
00199 
00200 Called from cache code to cause dirty pages of a section
00201 to be written back.  This doesn't affect the mapping.
00202 
00203 BaseOffset is the base at which to start writing in file space.
00204 FileSize is the length of the file as understood by the cache.
00205 
00206  */
00207 NTSTATUS
00208 NTAPI
00209 _MiFlushMappedSection(PVOID BaseAddress,
00210                       PLARGE_INTEGER BaseOffset,
00211                       PLARGE_INTEGER FileSize,
00212                       BOOLEAN WriteData,
00213                       const char *File,
00214                       int Line)
00215 {
00216     NTSTATUS Status = STATUS_SUCCESS;
00217     ULONG_PTR PageAddress;
00218     PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
00219     PMEMORY_AREA MemoryArea;
00220     PMM_SECTION_SEGMENT Segment;
00221     ULONG_PTR BeginningAddress, EndingAddress;
00222     LARGE_INTEGER ViewOffset;
00223     LARGE_INTEGER FileOffset;
00224     PFN_NUMBER Page;
00225     PPFN_NUMBER Pages;
00226     KIRQL OldIrql;
00227 
00228     DPRINT("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n",
00229            BaseAddress,
00230            BaseOffset->LowPart,
00231            FileSize,
00232            WriteData,
00233            File,
00234            Line);
00235 
00236     MmLockAddressSpace(AddressSpace);
00237     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
00238     if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress)
00239     {
00240         MmUnlockAddressSpace(AddressSpace);
00241         DPRINT("STATUS_NOT_MAPPED_DATA\n");
00242         return STATUS_NOT_MAPPED_DATA;
00243     }
00244     BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
00245     EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
00246     Segment = MemoryArea->Data.SectionData.Segment;
00247     ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
00248 
00249     ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
00250 
00251     MmLockSectionSegment(Segment);
00252 
00253     Pages = ExAllocatePool(NonPagedPool,
00254                            sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
00255 
00256     if (!Pages)
00257     {
00258         ASSERT(FALSE);
00259     }
00260 
00261     //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress);
00262 
00263     for (PageAddress = BeginningAddress;
00264          PageAddress < EndingAddress;
00265          PageAddress += PAGE_SIZE)
00266     {
00267         ULONG_PTR Entry;
00268         FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
00269         Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment,
00270                                              &FileOffset);
00271         Page = PFN_FROM_SSE(Entry);
00272         if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
00273             (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
00274             FileOffset.QuadPart < FileSize->QuadPart)
00275         {
00276             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00277             MmReferencePage(Page);
00278             KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00279             Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry;
00280         }
00281         else
00282         {
00283             Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
00284         }
00285     }
00286 
00287     MmUnlockSectionSegment(Segment);
00288     MmUnlockAddressSpace(AddressSpace);
00289 
00290     for (PageAddress = BeginningAddress;
00291          PageAddress < EndingAddress;
00292          PageAddress += PAGE_SIZE)
00293     {
00294         ULONG_PTR Entry;
00295         FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
00296         Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
00297         Page = PFN_FROM_SSE(Entry);
00298         if (Page)
00299         {
00300             if (WriteData) {
00301                 //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
00302                 Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
00303             } else
00304                 Status = STATUS_SUCCESS;
00305 
00306             if (NT_SUCCESS(Status)) {
00307                 MmLockAddressSpace(AddressSpace);
00308                 MmSetCleanAllRmaps(Page);
00309 
00310                 MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace),
00311                                  (PVOID)PageAddress,
00312                                  PAGE_READONLY);
00313 
00314                 MmLockSectionSegment(Segment);
00315                 Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
00316 
00317                 if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
00318                     MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
00319 
00320                 MmUnlockSectionSegment(Segment);
00321                 MmUnlockAddressSpace(AddressSpace);
00322             } else {
00323                 DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
00324                        FileOffset.u.HighPart,
00325                        FileOffset.u.LowPart,
00326                        (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
00327                        PageAddress,
00328                        Page,
00329                        FileSize->u.HighPart,
00330                        FileSize->u.LowPart,
00331                        &Segment->FileObject->FileName,
00332                        Status);
00333             }
00334             MmReleasePageMemoryConsumer(MC_CACHE, Page);
00335         }
00336     }
00337 
00338     ExFreePool(Pages);
00339 
00340     return Status;
00341 }
00342 
00343 /*
00344 
00345 This deletes a segment entirely including its page map.
00346 It must have been unmapped in every address space.
00347 
00348  */
00349 
00350 VOID
00351 NTAPI
00352 MmFinalizeSegment(PMM_SECTION_SEGMENT Segment)
00353 {
00354     KIRQL OldIrql = 0;
00355 
00356     DPRINT("Finalize segment %p\n", Segment);
00357 
00358     MmLockSectionSegment(Segment);
00359     RemoveEntryList(&Segment->ListOfSegments);
00360     if (Segment->Flags & MM_DATAFILE_SEGMENT) {
00361         KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
00362         if (Segment->Flags & MM_SEGMENT_FINALIZE) {
00363             KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
00364             MmUnlockSectionSegment(Segment);
00365             return;
00366         }
00367         Segment->Flags |= MM_SEGMENT_FINALIZE;
00368         DPRINTC("Finalizing data file segment %p\n", Segment);
00369 
00370         Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
00371         KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
00372         MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
00373         MmUnlockSectionSegment(Segment);
00374         DPRINT("Dereference file object %wZ\n", &Segment->FileObject->FileName);
00375         ObDereferenceObject(Segment->FileObject);
00376         DPRINT("Done with %wZ\n", &Segment->FileObject->FileName);
00377         Segment->FileObject = NULL;
00378     } else {
00379         DPRINTC("Finalizing segment %p\n", Segment);
00380         MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
00381         MmUnlockSectionSegment(Segment);
00382     }
00383     DPRINTC("Segment %p destroy\n", Segment);
00384     ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT);
00385 }
00386 
00387 NTSTATUS
00388 NTAPI
00389 MmCreateCacheSection(PROS_SECTION_OBJECT *SectionObject,
00390                      ACCESS_MASK DesiredAccess,
00391                      POBJECT_ATTRIBUTES ObjectAttributes,
00392                      PLARGE_INTEGER UMaximumSize,
00393                      ULONG SectionPageProtection,
00394                      ULONG AllocationAttributes,
00395                      PFILE_OBJECT FileObject)
00396 /*
00397  * Create a section backed by a data file.
00398  */
00399 {
00400     PROS_SECTION_OBJECT Section;
00401     NTSTATUS Status;
00402     LARGE_INTEGER MaximumSize;
00403     PMM_SECTION_SEGMENT Segment;
00404     IO_STATUS_BLOCK Iosb;
00405     CC_FILE_SIZES FileSizes;
00406     FILE_STANDARD_INFORMATION FileInfo;
00407     KIRQL OldIrql;
00408 
00409     DPRINT("MmCreateDataFileSection\n");
00410 
00411     /* Create the section */
00412     Status = ObCreateObject(ExGetPreviousMode(),
00413                             MmSectionObjectType,
00414                             ObjectAttributes,
00415                             ExGetPreviousMode(),
00416                             NULL,
00417                             sizeof(ROS_SECTION_OBJECT),
00418                             0,
00419                             0,
00420                             (PVOID*)(PVOID)&Section);
00421     if (!NT_SUCCESS(Status))
00422     {
00423         DPRINT("Failed: %x\n", Status);
00424         return Status;
00425     }
00426 
00427     /* Initialize it */
00428     RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
00429     Section->Type = 'SC';
00430     Section->Size = 'TN';
00431     Section->SectionPageProtection = SectionPageProtection;
00432     Section->AllocationAttributes = AllocationAttributes;
00433     Section->Segment = NULL;
00434 
00435     Section->FileObject = FileObject;
00436 
00437     DPRINT("Getting original file size\n");
00438     /* A hack: If we're cached, we can overcome deadlocking with the upper
00439     * layer filesystem call by retriving the object sizes from the cache
00440     * which is made to keep track.  If I had to guess, they were figuring
00441     * out a similar problem.
00442     */
00443     if (!CcGetFileSizes(FileObject, &FileSizes))
00444     {
00445         ULONG Information;
00446         /*
00447         * FIXME: This is propably not entirely correct. We can't look into
00448         * the standard FCB header because it might not be initialized yet
00449         * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
00450         * standard file information is filled on first request).
00451         */
00452         DPRINT("Querying info\n");
00453         Status = IoQueryFileInformation(FileObject,
00454                                         FileStandardInformation,
00455                                         sizeof(FILE_STANDARD_INFORMATION),
00456                                         &FileInfo,
00457                                         &Information);
00458         Iosb.Information = Information;
00459         DPRINT("Query => %x\n", Status);
00460 
00461         if (!NT_SUCCESS(Status))
00462         {
00463             DPRINT("Status %x\n", Status);
00464             ObDereferenceObject(Section);
00465             return Status;
00466         }
00467         ASSERT(Status != STATUS_PENDING);
00468 
00469         FileSizes.ValidDataLength = FileInfo.EndOfFile;
00470         FileSizes.FileSize = FileInfo.EndOfFile;
00471     }
00472     DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
00473 
00474     /*
00475     * FIXME: Revise this once a locking order for file size changes is
00476     * decided
00477     *
00478     * We're handed down a maximum size in every case.  Should we still check at all?
00479     */
00480     if (UMaximumSize != NULL && UMaximumSize->QuadPart)
00481     {
00482         DPRINT("Taking maximum %x\n", UMaximumSize->LowPart);
00483         MaximumSize.QuadPart = UMaximumSize->QuadPart;
00484     }
00485     else
00486     {
00487         DPRINT("Got file size %08x%08x\n",
00488                FileSizes.FileSize.u.HighPart,
00489                FileSizes.FileSize.u.LowPart);
00490 
00491         MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
00492     }
00493 
00494     /* Mapping zero-sized files isn't allowed. */
00495     if (MaximumSize.QuadPart == 0)
00496     {
00497         DPRINT("Zero size file\n");
00498         ObDereferenceObject(Section);
00499         return STATUS_FILE_INVALID;
00500     }
00501 
00502     Segment = ExAllocatePoolWithTag(NonPagedPool,
00503                                     sizeof(MM_SECTION_SEGMENT),
00504                                     TAG_MM_SECTION_SEGMENT);
00505     if (Segment == NULL)
00506     {
00507         DPRINT("Failed: STATUS_NO_MEMORY\n");
00508         ObDereferenceObject(Section);
00509         return STATUS_NO_MEMORY;
00510     }
00511 
00512     DPRINT("Zeroing %x\n", Segment);
00513     RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
00514     ExInitializeFastMutex(&Segment->Lock);
00515 
00516     Segment->ReferenceCount = 1;
00517     Segment->Locked = TRUE;
00518     RtlZeroMemory(&Segment->Image, sizeof(Segment->Image));
00519     Section->Segment = Segment;
00520 
00521     KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql);
00522     /*
00523     * If this file hasn't been mapped as a data file before then allocate a
00524     * section segment to describe the data file mapping
00525     */
00526     if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
00527     {
00528         FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
00529         KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
00530 
00531         /*
00532         * Set the lock before assigning the segment to the file object
00533         */
00534         ExAcquireFastMutex(&Segment->Lock);
00535 
00536         DPRINT("Filling out Segment info (No previous data section)\n");
00537         ObReferenceObject(FileObject);
00538         Segment->FileObject = FileObject;
00539         Segment->Protection = SectionPageProtection;
00540         Segment->Flags = MM_DATAFILE_SEGMENT;
00541         memset(&Segment->Image, 0, sizeof(Segment->Image));
00542         Segment->WriteCopy = FALSE;
00543 
00544         if (AllocationAttributes & SEC_RESERVE)
00545         {
00546             Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
00547         }
00548         else
00549         {
00550             Segment->RawLength.QuadPart = MaximumSize.QuadPart;
00551             Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
00552         }
00553         MiInitializeSectionPageTable(Segment);
00554         InsertHeadList(&MiSegmentList, &Segment->ListOfSegments);
00555     }
00556     else
00557     {
00558         KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
00559         DPRINTC("Free Segment %x\n", Segment);
00560         ExFreePool(Segment);
00561 
00562         DPRINT("Filling out Segment info (previous data section)\n");
00563 
00564         /*
00565         * If the file is already mapped as a data file then we may need
00566         * to extend it
00567         */
00568         Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->DataSectionObject;
00569         Section->Segment = Segment;
00570         (void)InterlockedIncrementUL(&Segment->ReferenceCount);
00571 
00572         MmLockSectionSegment(Segment);
00573 
00574         if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
00575             !(AllocationAttributes & SEC_RESERVE))
00576         {
00577             Segment->RawLength.QuadPart = MaximumSize.QuadPart;
00578             Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
00579         }
00580     }
00581 
00582     MmUnlockSectionSegment(Segment);
00583 
00584     Section->MaximumSize.QuadPart = MaximumSize.QuadPart;
00585 
00586     /* Extend file if section is longer */
00587     DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
00588            MaximumSize.u.HighPart,
00589            MaximumSize.u.LowPart,
00590            FileSizes.ValidDataLength.u.HighPart,
00591            FileSizes.ValidDataLength.u.LowPart);
00592     if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
00593     {
00594         DPRINT("Changing file size to %08x%08x, segment %x\n",
00595                MaximumSize.u.HighPart,
00596                MaximumSize.u.LowPart,
00597                Segment);
00598 
00599         Status = IoSetInformation(FileObject,
00600                                   FileEndOfFileInformation,
00601                                   sizeof(LARGE_INTEGER),
00602                                   &MaximumSize);
00603 
00604         DPRINT("Change: Status %x\n", Status);
00605         if (!NT_SUCCESS(Status))
00606         {
00607             DPRINT("Could not expand section\n");
00608             ObDereferenceObject(Section);
00609             return Status;
00610         }
00611     }
00612 
00613     DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
00614 
00615     *SectionObject = Section;
00616     return STATUS_SUCCESS;
00617 }
00618 
00619 NTSTATUS
00620 NTAPI
00621 _MiMapViewOfSegment(PMMSUPPORT AddressSpace,
00622                     PMM_SECTION_SEGMENT Segment,
00623                     PVOID* BaseAddress,
00624                     SIZE_T ViewSize,
00625                     ULONG Protect,
00626                     PLARGE_INTEGER ViewOffset,
00627                     ULONG AllocationType,
00628                     const char *file,
00629                     int line)
00630 {
00631     PMEMORY_AREA MArea;
00632     NTSTATUS Status;
00633     PHYSICAL_ADDRESS BoundaryAddressMultiple;
00634 
00635     BoundaryAddressMultiple.QuadPart = 0;
00636 
00637     Status = MmCreateMemoryArea(AddressSpace,
00638                                 MEMORY_AREA_CACHE,
00639                                 BaseAddress,
00640                                 ViewSize,
00641                                 Protect,
00642                                 &MArea,
00643                                 FALSE,
00644                                 AllocationType,
00645                                 BoundaryAddressMultiple);
00646 
00647     if (!NT_SUCCESS(Status))
00648     {
00649         DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
00650                (*BaseAddress),
00651                (char*)(*BaseAddress) + ViewSize,
00652                Status);
00653 
00654         return Status;
00655     }
00656 
00657     DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n",
00658             MmGetAddressSpaceOwner(AddressSpace),
00659             *BaseAddress,
00660             Segment,
00661             ViewOffset ? ViewOffset->LowPart : 0,
00662             ViewSize,
00663             Segment->FileObject ? &Segment->FileObject->FileName : NULL,
00664             file,
00665             line);
00666 
00667     MArea->Data.SectionData.Segment = Segment;
00668     if (ViewOffset)
00669         MArea->Data.SectionData.ViewOffset = *ViewOffset;
00670     else
00671         MArea->Data.SectionData.ViewOffset.QuadPart = 0;
00672 
00673 #if 0
00674     MArea->NotPresent = MmNotPresentFaultPageFile;
00675     MArea->AccessFault = MiCowSectionPage;
00676     MArea->PageOut = MmPageOutPageFileView;
00677 #endif
00678 
00679     MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
00680                        ViewSize,
00681                        0,
00682                        Protect);
00683 
00684     DPRINTC("MiMapViewOfSegment(P %x, A %x, T %x)\n",
00685             MmGetAddressSpaceOwner(AddressSpace),
00686             *BaseAddress,
00687             MArea->Type);
00688 
00689     return STATUS_SUCCESS;
00690 }
00691 
00692 /*
00693 
00694 Completely remove the page at FileOffset in Segment.  The page must not
00695 be mapped.
00696 
00697 */
00698 
00699 VOID
00700 NTAPI
00701 MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment,
00702                   PLARGE_INTEGER FileOffset)
00703 {
00704     ULONG_PTR Entry;
00705     PFILE_OBJECT FileObject = Segment->FileObject;
00706 
00707     Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
00708     DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
00709             Segment,
00710             FileOffset->HighPart,
00711             FileOffset->LowPart,
00712             Entry);
00713 
00714     if (Entry && !IS_SWAP_FROM_SSE(Entry))
00715     {
00716         // The segment is carrying a dirty page.
00717         PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
00718         if (IS_DIRTY_SSE(Entry) && FileObject)
00719         {
00720             DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n",
00721                    Segment,
00722                    &FileObject->FileName,
00723                    FileOffset->u.HighPart,
00724                    FileOffset->u.LowPart);
00725 
00726             MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
00727         }
00728         DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n",
00729                 OldPage,
00730                 FileOffset->LowPart,
00731                 Segment,
00732                 MmGetReferenceCountPage(OldPage),
00733                 Entry,
00734                 IS_DIRTY_SSE(Entry) ? "true" : "false");
00735 
00736         MmSetPageEntrySectionSegment(Segment, FileOffset, 0);
00737         MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
00738     }
00739     else if (IS_SWAP_FROM_SSE(Entry))
00740     {
00741         DPRINT("Free swap\n");
00742         MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
00743     }
00744 
00745     DPRINT("Done\n");
00746 }
00747 
00748 VOID
00749 MmFreeCacheSectionPage(PVOID Context,
00750                        MEMORY_AREA* MemoryArea,
00751                        PVOID Address,
00752                        PFN_NUMBER Page,
00753                        SWAPENTRY SwapEntry,
00754                        BOOLEAN Dirty)
00755 {
00756     ULONG_PTR Entry;
00757     PVOID *ContextData = Context;
00758     PMMSUPPORT AddressSpace;
00759     PEPROCESS Process;
00760     PMM_SECTION_SEGMENT Segment;
00761     LARGE_INTEGER Offset;
00762 
00763     DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n",
00764            MmGetAddressSpaceOwner(ContextData[0]),
00765            Address,
00766            Page,
00767            SwapEntry,
00768            Dirty);
00769 
00770     AddressSpace = ContextData[0];
00771     Process = MmGetAddressSpaceOwner(AddressSpace);
00772     Address = (PVOID)PAGE_ROUND_DOWN(Address);
00773     Segment = ContextData[1];
00774     Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
00775                       MemoryArea->Data.SectionData.ViewOffset.QuadPart;
00776 
00777     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
00778 
00779     if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
00780     {
00781         DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
00782         MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
00783     }
00784     if (Page)
00785     {
00786         DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
00787         MmSetSavedSwapEntryPage(Page, 0);
00788         MmDeleteRmap(Page, Process, Address);
00789         MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
00790         MmReleasePageMemoryConsumer(MC_CACHE, Page);
00791     }
00792     if (SwapEntry != 0)
00793     {
00794         MmFreeSwapPage(SwapEntry);
00795     }
00796 }
00797 
00798 NTSTATUS
00799 NTAPI
00800 MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace,
00801                           PVOID BaseAddress)
00802 {
00803     PVOID Context[2];
00804     PMEMORY_AREA MemoryArea;
00805     PMM_SECTION_SEGMENT Segment;
00806 
00807     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
00808     if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
00809     {
00810         ASSERT(MemoryArea);
00811         return STATUS_UNSUCCESSFUL;
00812     }
00813 
00814     MemoryArea->DeleteInProgress = TRUE;
00815     Segment = MemoryArea->Data.SectionData.Segment;
00816     MemoryArea->Data.SectionData.Segment = NULL;
00817 
00818     MmLockSectionSegment(Segment);
00819 
00820     Context[0] = AddressSpace;
00821     Context[1] = Segment;
00822 
00823     DPRINT("MmFreeMemoryArea(%x,%x)\n",
00824            MmGetAddressSpaceOwner(AddressSpace),
00825            MemoryArea->StartingAddress);
00826 
00827     MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
00828 
00829     MmUnlockSectionSegment(Segment);
00830 
00831     DPRINTC("MiUnmapViewOfSegment %x %x %x\n",
00832             MmGetAddressSpaceOwner(AddressSpace),
00833             BaseAddress,
00834             Segment);
00835 
00836     return STATUS_SUCCESS;
00837 }
00838 
00839 NTSTATUS
00840 NTAPI
00841 MmExtendCacheSection(PROS_SECTION_OBJECT Section,
00842                      PLARGE_INTEGER NewSize,
00843                      BOOLEAN ExtendFile)
00844 {
00845     LARGE_INTEGER OldSize;
00846     PMM_SECTION_SEGMENT Segment = Section->Segment;
00847     DPRINT("Extend Segment %x\n", Segment);
00848 
00849     MmLockSectionSegment(Segment);
00850     OldSize.QuadPart = Segment->RawLength.QuadPart;
00851     MmUnlockSectionSegment(Segment);
00852 
00853     DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
00854            OldSize.u.HighPart, OldSize.u.LowPart,
00855            NewSize->u.HighPart, NewSize->u.LowPart);
00856 
00857     if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
00858     {
00859         NTSTATUS Status;
00860 
00861         Status = IoSetInformation(Segment->FileObject,
00862                                   FileEndOfFileInformation,
00863                                   sizeof(LARGE_INTEGER),
00864                                   NewSize);
00865 
00866         if (!NT_SUCCESS(Status)) return Status;
00867     }
00868 
00869     MmLockSectionSegment(Segment);
00870     Segment->RawLength.QuadPart = NewSize->QuadPart;
00871     Segment->Length.QuadPart = MAX(Segment->Length.QuadPart,
00872                                    (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart));
00873     MmUnlockSectionSegment(Segment);
00874     return STATUS_SUCCESS;
00875 }
00876 
00877 NTSTATUS
00878 NTAPI
00879 MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment,
00880                                     OUT PVOID *MappedBase,
00881                                     PLARGE_INTEGER FileOffset,
00882                                     IN OUT PULONG ViewSize)
00883 {
00884     PMMSUPPORT AddressSpace;
00885     NTSTATUS Status;
00886 
00887     DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n",
00888            FileOffset->HighPart,
00889            FileOffset->LowPart);
00890 
00891     AddressSpace = MmGetKernelAddressSpace();
00892 
00893     MmLockAddressSpace(AddressSpace);
00894     MmLockSectionSegment(Segment);
00895 
00896     Status = MiMapViewOfSegment(AddressSpace,
00897                                 Segment,
00898                                 MappedBase,
00899                                 *ViewSize,
00900                                 PAGE_READWRITE,
00901                                 FileOffset,
00902                                 0);
00903 
00904     MmUnlockSectionSegment(Segment);
00905     MmUnlockAddressSpace(AddressSpace);
00906 
00907     return Status;
00908 }
00909 
00910 /*
00911  * @implemented
00912  */
00913 NTSTATUS NTAPI
00914 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
00915 {
00916     PMMSUPPORT AddressSpace;
00917     NTSTATUS Status;
00918 
00919     DPRINT("MmUnmapViewInSystemSpace() called\n");
00920 
00921     AddressSpace = MmGetKernelAddressSpace();
00922 
00923     Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
00924 
00925     return Status;
00926 }
00927 
00928 /* EOF */

Generated on Sun May 27 2012 04:28:09 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.