[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / cache / section / data.c
index 89cdf74..faa785d 100644 (file)
  *                  Herve Poussineau
  */
 
+/*
+
+A note on this code:
+
+Unlike the previous section code, this code does not rely on an active map
+for a page to exist in a data segment.  Each mapping contains a large integer
+offset to map at, and the segment always represents the entire section space
+from zero to the maximum long long.  This allows us to associate one single
+page map with each file object, and to let each mapping view an offset into
+the overall mapped file.  Temporarily unmapping the file has no effect on the
+section membership.
+
+This necessitates a change in the section page table implementation, which is
+now an RtlGenericTable.  This will be elaborated more in sptab.c.  One upshot
+of this change is that a mapping of a small files takes a bit more than 1/4
+of the size in nonpaged kernel space as it did previously.
+
+When we need other threads that may be competing for the same page fault to
+wait, we have a mechanism seperate from PageOps for dealing with that, which
+was suggested by Travis Geiselbrecht after a conversation I had with Alex
+Ionescu.  That mechanism is the MM_WAIT_ENTRY, which is the all-ones SWAPENTRY.
+
+When we wish for other threads to know that we're waiting and will finish
+handling a page fault, we place the swap entry MM_WAIT_ENTRY in the page table
+at the fault address (this works on either the section page table or a process
+address space), perform any blocking operations required, then replace the
+entry.
+
+*/
+
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
 #include "../newcc.h"
 #define NDEBUG
 #include <debug.h>
+#include "../mm/ARM3/miarm.h"
 
 #define DPRINTC DPRINT
 
+LIST_ENTRY MiSegmentList;
+
 extern KEVENT MpwThreadEvent;
 extern KSPIN_LOCK MiSectionPageTableLock;
+extern PMMWSL MmWorkingSetList;
 
 /* GLOBALS *******************************************************************/
 
-ULONG_PTR MmSubsectionBase;
-BOOLEAN MmAllocationFragment;
-
-NTSTATUS
-NTAPI
-MiSimpleRead
-(PFILE_OBJECT FileObject, 
- PLARGE_INTEGER FileOffset,
- PVOID Buffer, 
- ULONG Length,
- PIO_STATUS_BLOCK ReadStatus);
-
 static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
 {
-  ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
-  ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
+    ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
+    ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
 };
 
 /* FUNCTIONS *****************************************************************/
@@ -81,611 +103,806 @@ static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
 
 VOID
 NTAPI
-_MmLockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
+_MmLockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
 {
-       DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
-       ExAcquireFastMutex(&Segment->Lock);
+    //DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
+    ExAcquireFastMutex(&Segment->Lock);
+    Segment->Locked = TRUE;
 }
 
 VOID
 NTAPI
-_MmUnlockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
+_MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment, const char *file, int line)
 {
-       ExReleaseFastMutex(&Segment->Lock);
-       DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
+    ASSERT(Segment->Locked);
+    Segment->Locked = FALSE;
+    ExReleaseFastMutex(&Segment->Lock);
+    //DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
 }
 
 NTSTATUS
 NTAPI
-MiZeroFillSection
-(PVOID Address,
- PLARGE_INTEGER FileOffsetPtr,
- ULONG Length)
+MiZeroFillSection(PVOID Address, PLARGE_INTEGER FileOffsetPtr, ULONG Length)
 {
-       PFN_NUMBER Page;
-       PMMSUPPORT AddressSpace;
-       PMEMORY_AREA MemoryArea;
-       PMM_CACHE_SECTION_SEGMENT Segment;
-       LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
-       DPRINT1("MiZeroFillSection(Address %x,Offset %x,Length %x)\n", Address, FileOffset.LowPart, Length);
-       AddressSpace = MmGetKernelAddressSpace();
-       MmLockAddressSpace(AddressSpace);
-       MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
-       MmUnlockAddressSpace(AddressSpace);
-       if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) 
-       {
-               return STATUS_NOT_MAPPED_DATA;
-       }
-
-       Segment = MemoryArea->Data.CacheData.Segment;
-       End.QuadPart = FileOffset.QuadPart + Length;
-       End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
-       FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
-       FirstMapped.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
-       DPRINT
-               ("Pulling zero pages for %08x%08x-%08x%08x\n",
-                FileOffset.u.HighPart, FileOffset.u.LowPart,
-                End.u.HighPart, End.u.LowPart);
-       while (FileOffset.QuadPart < End.QuadPart)
-       {
-               PVOID Address;
-               ULONG Entry;
-
-               if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
-                       break;
-
-               MmLockAddressSpace(AddressSpace);
-               MmLockCacheSectionSegment(Segment);
-
-               Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
-               if (Entry == 0)
-               {
-                       MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
-                       Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
-                       MmReferencePage(Page);
-                       MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1);
-                       MmInsertRmap(Page, NULL, Address);
-               }
-               else
-                       MmReleasePageMemoryConsumer(MC_CACHE, Page);
-
-               MmUnlockCacheSectionSegment(Segment);
-               MmUnlockAddressSpace(AddressSpace);
-
-               FileOffset.QuadPart += PAGE_SIZE;
-       }
-       return STATUS_SUCCESS;
+    PFN_NUMBER Page;
+    PMMSUPPORT AddressSpace;
+    PMEMORY_AREA MemoryArea;
+    PMM_SECTION_SEGMENT Segment;
+    LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
+    KIRQL OldIrql;
+
+    DPRINT("MiZeroFillSection(Address %x,Offset %x,Length %x)\n",
+           Address,
+           FileOffset.LowPart,
+           Length);
+
+    AddressSpace = MmGetKernelAddressSpace();
+
+    MmLockAddressSpace(AddressSpace);
+    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+    MmUnlockAddressSpace(AddressSpace);
+    if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW || MemoryArea->DeleteInProgress)
+    {
+        return STATUS_NOT_MAPPED_DATA;
+    }
+
+    Segment = MemoryArea->Data.SectionData.Segment;
+    End.QuadPart = FileOffset.QuadPart + Length;
+    End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
+    FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
+    FirstMapped.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
+    DPRINT("Pulling zero pages for %08x%08x-%08x%08x\n",
+           FileOffset.u.HighPart, FileOffset.u.LowPart,
+           End.u.HighPart, End.u.LowPart);
+
+    while (FileOffset.QuadPart < End.QuadPart)
+    {
+        PVOID CurrentAddress;
+        ULONG_PTR Entry;
+
+        if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
+            break;
+
+        MmLockAddressSpace(AddressSpace);
+        MmLockSectionSegment(Segment);
+
+        Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
+        if (Entry == 0)
+        {
+            MmSetPageEntrySectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
+            CurrentAddress = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
+
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+            MmReferencePage(Page);
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+            MmCreateVirtualMapping(NULL, CurrentAddress, PAGE_READWRITE, &Page, 1);
+            MmInsertRmap(Page, NULL, CurrentAddress);
+        }
+        else
+        {
+            MmReleasePageMemoryConsumer(MC_CACHE, Page);
+        }
+
+        MmUnlockSectionSegment(Segment);
+        MmUnlockAddressSpace(AddressSpace);
+
+        FileOffset.QuadPart += PAGE_SIZE;
+    }
+    return STATUS_SUCCESS;
 }
 
+/*
+
+MiFlushMappedSection
+
+Called from cache code to cause dirty pages of a section
+to be written back.  This doesn't affect the mapping.
+
+BaseOffset is the base at which to start writing in file space.
+FileSize is the length of the file as understood by the cache.
+
+ */
 NTSTATUS
 NTAPI
-_MiFlushMappedSection
-(PVOID BaseAddress,
- PLARGE_INTEGER BaseOffset,
- PLARGE_INTEGER FileSize,
- BOOLEAN WriteData,
- const char *File,
- int Line)
+_MiFlushMappedSection(PVOID BaseAddress,
+                      PLARGE_INTEGER BaseOffset,
+                      PLARGE_INTEGER FileSize,
+                      BOOLEAN WriteData,
+                      const char *File,
+                      int Line)
 {
-       NTSTATUS Status = STATUS_SUCCESS;
-       ULONG_PTR PageAddress;
-       PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
-       PMEMORY_AREA MemoryArea;
-       PMM_CACHE_SECTION_SEGMENT Segment;
-       ULONG_PTR BeginningAddress, EndingAddress;
-       LARGE_INTEGER ViewOffset;
-       LARGE_INTEGER FileOffset;
-       PFN_NUMBER Page;
-       PPFN_NUMBER Pages;
-
-       DPRINT1("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n", BaseAddress, BaseOffset->LowPart, FileSize, WriteData, File, Line);
-
-       MmLockAddressSpace(AddressSpace);
-       MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
-       if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) 
-       {
-               MmUnlockAddressSpace(AddressSpace);
-               return STATUS_NOT_MAPPED_DATA;
-       }
-       BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
-       EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
-       Segment = MemoryArea->Data.CacheData.Segment;
-       ViewOffset.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
-
-       ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
-
-       MmLockCacheSectionSegment(Segment);
-
-       Pages = ExAllocatePool
-               (NonPagedPool, 
-                sizeof(PFN_NUMBER) * 
-                ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
-
-       if (!Pages)
-       {
-               ASSERT(FALSE);
-       }
-
-       for (PageAddress = BeginningAddress;
-                PageAddress < EndingAddress;
-                PageAddress += PAGE_SIZE)
-       {
-               ULONG Entry;
-               FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
-               Entry =
-                       MiGetPageEntryCacheSectionSegment
-                       (MemoryArea->Data.CacheData.Segment, 
-                        &FileOffset);
-               Page = PFN_FROM_SSE(Entry);
-               if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) && 
-                       (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
-                       FileOffset.QuadPart < FileSize->QuadPart)
-               {
-                       Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Page;
-               }
-               else
-                       Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
-       }
-
-       MmUnlockCacheSectionSegment(Segment);
-       MmUnlockAddressSpace(AddressSpace);
-
-       for (PageAddress = BeginningAddress;
-                PageAddress < EndingAddress;
-                PageAddress += PAGE_SIZE)
-       {
-               FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
-               Page = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
-               if (Page)
-               {
-                       ULONG Entry;
-                       if (WriteData) {
-                               DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
-                               Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
-                       } else
-                               Status = STATUS_SUCCESS;
-
-                       if (NT_SUCCESS(Status)) {
-                               MmLockAddressSpace(AddressSpace);
-                               MmSetCleanAllRmaps(Page);
-                               MmLockCacheSectionSegment(Segment);
-                               Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
-                               if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
-                                       MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
-                               MmUnlockCacheSectionSegment(Segment);
-                               MmUnlockAddressSpace(AddressSpace);
-                       } else {
-                               DPRINT
-                                       ("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
-                                        FileOffset.u.HighPart, FileOffset.u.LowPart,
-                                        (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
-                                        PageAddress,
-                                        Page,
-                                        FileSize->u.HighPart,
-                                        FileSize->u.LowPart,
-                                        &Segment->FileObject->FileName,
-                                        Status);
-                       }
-               }
-       }
-
-       ExFreePool(Pages);
-
-       return Status;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG_PTR PageAddress;
+    PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
+    PMEMORY_AREA MemoryArea;
+    PMM_SECTION_SEGMENT Segment;
+    ULONG_PTR BeginningAddress, EndingAddress;
+    LARGE_INTEGER ViewOffset;
+    LARGE_INTEGER FileOffset;
+    PFN_NUMBER Page;
+    PPFN_NUMBER Pages;
+    KIRQL OldIrql;
+
+    DPRINT("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n",
+           BaseAddress,
+           BaseOffset->LowPart,
+           FileSize,
+           WriteData,
+           File,
+           Line);
+
+    MmLockAddressSpace(AddressSpace);
+    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
+    if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_CACHE || MemoryArea->DeleteInProgress)
+    {
+        MmUnlockAddressSpace(AddressSpace);
+        DPRINT("STATUS_NOT_MAPPED_DATA\n");
+        return STATUS_NOT_MAPPED_DATA;
+    }
+    BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
+    EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
+    Segment = MemoryArea->Data.SectionData.Segment;
+    ViewOffset.QuadPart = MemoryArea->Data.SectionData.ViewOffset.QuadPart;
+
+    ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
+
+    MmLockSectionSegment(Segment);
+
+    Pages = ExAllocatePool(NonPagedPool,
+                           sizeof(PFN_NUMBER) * ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
+
+    if (!Pages)
+    {
+        ASSERT(FALSE);
+    }
+
+    //DPRINT("Getting pages in range %08x-%08x\n", BeginningAddress, EndingAddress);
+
+    for (PageAddress = BeginningAddress;
+         PageAddress < EndingAddress;
+         PageAddress += PAGE_SIZE)
+    {
+        ULONG_PTR Entry;
+        FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
+        Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment,
+                                             &FileOffset);
+        Page = PFN_FROM_SSE(Entry);
+        if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
+            (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
+            FileOffset.QuadPart < FileSize->QuadPart)
+        {
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+            MmReferencePage(Page);
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Entry;
+        }
+        else
+        {
+            Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
+        }
+    }
+
+    MmUnlockSectionSegment(Segment);
+    MmUnlockAddressSpace(AddressSpace);
+
+    for (PageAddress = BeginningAddress;
+         PageAddress < EndingAddress;
+         PageAddress += PAGE_SIZE)
+    {
+        ULONG_PTR Entry;
+        FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
+        Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
+        Page = PFN_FROM_SSE(Entry);
+        if (Page)
+        {
+            if (WriteData) {
+                //DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
+                Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
+            } else
+                Status = STATUS_SUCCESS;
+
+            if (NT_SUCCESS(Status)) {
+                MmLockAddressSpace(AddressSpace);
+                MmSetCleanAllRmaps(Page);
+
+                MmSetPageProtect(MmGetAddressSpaceOwner(AddressSpace),
+                                 (PVOID)PageAddress,
+                                 PAGE_READONLY);
+
+                MmLockSectionSegment(Segment);
+                Entry = MmGetPageEntrySectionSegment(Segment, &FileOffset);
+
+                if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
+                    MmSetPageEntrySectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
+
+                MmUnlockSectionSegment(Segment);
+                MmUnlockAddressSpace(AddressSpace);
+            } else {
+                DPRINT("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
+                       FileOffset.u.HighPart,
+                       FileOffset.u.LowPart,
+                       (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
+                       PageAddress,
+                       Page,
+                       FileSize->u.HighPart,
+                       FileSize->u.LowPart,
+                       &Segment->FileObject->FileName,
+                       Status);
+            }
+            MmReleasePageMemoryConsumer(MC_CACHE, Page);
+        }
+    }
+
+    ExFreePool(Pages);
+
+    return Status;
 }
 
+/*
+
+This deletes a segment entirely including its page map.
+It must have been unmapped in every address space.
+
+ */
+
 VOID
 NTAPI
-MmFinalizeSegment(PMM_CACHE_SECTION_SEGMENT Segment)
+MmFinalizeSegment(PMM_SECTION_SEGMENT Segment)
 {
-       KIRQL OldIrql = 0;
-
-       MmLockCacheSectionSegment(Segment);
-       if (Segment->Flags & MM_DATAFILE_SEGMENT) {
-               KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
-               if (Segment->Flags & MM_SEGMENT_FINALIZE) {
-                       KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
-                       MmUnlockCacheSectionSegment(Segment);
-                       return;
-               } else {
-                       Segment->Flags |= MM_SEGMENT_FINALIZE;
-               }
-       }
-       DPRINTC("Finalizing segment %x\n", Segment);
-       if (Segment->Flags & MM_DATAFILE_SEGMENT)
-       {
-               //Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
-               KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
-               MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
-               MmUnlockCacheSectionSegment(Segment);
-               ObDereferenceObject(Segment->FileObject);
-       } else {
-               MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
-               MmUnlockCacheSectionSegment(Segment);           
-       }
-       DPRINTC("Segment %x destroy\n", Segment);
-       ExFreePool(Segment);
+    KIRQL OldIrql = 0;
+
+    DPRINT("Finalize segment %p\n", Segment);
+
+    MmLockSectionSegment(Segment);
+    RemoveEntryList(&Segment->ListOfSegments);
+    if (Segment->Flags & MM_DATAFILE_SEGMENT) {
+        KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
+        if (Segment->Flags & MM_SEGMENT_FINALIZE) {
+            KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
+            MmUnlockSectionSegment(Segment);
+            return;
+        }
+        Segment->Flags |= MM_SEGMENT_FINALIZE;
+        DPRINTC("Finalizing data file segment %p\n", Segment);
+
+        Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
+        KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
+        MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
+        MmUnlockSectionSegment(Segment);
+        DPRINT("Dereference file object %wZ\n", &Segment->FileObject->FileName);
+        ObDereferenceObject(Segment->FileObject);
+        DPRINT("Done with %wZ\n", &Segment->FileObject->FileName);
+        Segment->FileObject = NULL;
+    } else {
+        DPRINTC("Finalizing segment %p\n", Segment);
+        MmFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
+        MmUnlockSectionSegment(Segment);
+    }
+    DPRINTC("Segment %p destroy\n", Segment);
+    ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT);
 }
 
 NTSTATUS
 NTAPI
-MmCreateCacheSection
-(PMM_CACHE_SECTION_SEGMENT *SegmentObject,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes,
- PLARGE_INTEGER UMaximumSize,
- ULONG SectionPageProtection,
- ULONG AllocationAttributes,
- PFILE_OBJECT FileObject)
+MmCreateCacheSection(PROS_SECTION_OBJECT *SectionObject,
+                     ACCESS_MASK DesiredAccess,
+                     POBJECT_ATTRIBUTES ObjectAttributes,
+                     PLARGE_INTEGER UMaximumSize,
+                     ULONG SectionPageProtection,
+                     ULONG AllocationAttributes,
+                     PFILE_OBJECT FileObject)
 /*
- * Create a section backed by a data file
+ * Create a section backed by a data file.
  */
 {
-   NTSTATUS Status;
-   ULARGE_INTEGER MaximumSize;
-   PMM_CACHE_SECTION_SEGMENT Segment;
-   ULONG FileAccess;
-   IO_STATUS_BLOCK Iosb;
-   CC_FILE_SIZES FileSizes;
-   FILE_STANDARD_INFORMATION FileInfo;
-
-   /*
-    * Check file access required
-    */
-   if (SectionPageProtection & PAGE_READWRITE ||
-         SectionPageProtection & PAGE_EXECUTE_READWRITE)
-   {
-      FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
-   }
-   else
-   {
-      FileAccess = FILE_READ_DATA;
-   }
-
-   /*
-    * Reference the file handle
-    */
-   ObReferenceObject(FileObject);
-
-   DPRINT("Getting original file size\n");
-   /* A hack: If we're cached, we can overcome deadlocking with the upper
+    PROS_SECTION_OBJECT Section;
+    NTSTATUS Status;
+    LARGE_INTEGER MaximumSize;
+    PMM_SECTION_SEGMENT Segment;
+    IO_STATUS_BLOCK Iosb;
+    CC_FILE_SIZES FileSizes;
+    FILE_STANDARD_INFORMATION FileInfo;
+    KIRQL OldIrql;
+
+    DPRINT("MmCreateDataFileSection\n");
+
+    /* Create the section */
+    Status = ObCreateObject(ExGetPreviousMode(),
+                            MmSectionObjectType,
+                            ObjectAttributes,
+                            ExGetPreviousMode(),
+                            NULL,
+                            sizeof(ROS_SECTION_OBJECT),
+                            0,
+                            0,
+                            (PVOID*)(PVOID)&Section);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Failed: %x\n", Status);
+        return Status;
+    }
+
+    /* Initialize it */
+    RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
+    Section->Type = 'SC';
+    Section->Size = 'TN';
+    Section->SectionPageProtection = SectionPageProtection;
+    Section->AllocationAttributes = AllocationAttributes;
+    Section->Segment = NULL;
+
+    Section->FileObject = FileObject;
+
+    DPRINT("Getting original file size\n");
+    /* A hack: If we're cached, we can overcome deadlocking with the upper
     * layer filesystem call by retriving the object sizes from the cache
     * which is made to keep track.  If I had to guess, they were figuring
     * out a similar problem.
     */
-   if (!CcGetFileSizes(FileObject, &FileSizes))
-   {
-       /*
-               * FIXME: This is propably not entirely correct. We can't look into
-               * the standard FCB header because it might not be initialized yet
-               * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
-               * standard file information is filled on first request).
-               */
-       Status = IoQueryFileInformation
-          (FileObject,
-           FileStandardInformation,
-           sizeof(FILE_STANDARD_INFORMATION),
-           &FileInfo,
-           &Iosb.Information);
-
-       if (!NT_SUCCESS(Status))
-       {
-                  return Status;
-       }
-
-          ASSERT(Status != STATUS_PENDING);
-
-       FileSizes.ValidDataLength = FileInfo.EndOfFile;
-       FileSizes.FileSize = FileInfo.EndOfFile;
-   }
-   DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
-
-   /*
+    if (!CcGetFileSizes(FileObject, &FileSizes))
+    {
+        ULONG Information;
+        /*
+        * FIXME: This is propably not entirely correct. We can't look into
+        * the standard FCB header because it might not be initialized yet
+        * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
+        * standard file information is filled on first request).
+        */
+        DPRINT("Querying info\n");
+        Status = IoQueryFileInformation(FileObject,
+                                        FileStandardInformation,
+                                        sizeof(FILE_STANDARD_INFORMATION),
+                                        &FileInfo,
+                                        &Information);
+        Iosb.Information = Information;
+        DPRINT("Query => %x\n", Status);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("Status %x\n", Status);
+            ObDereferenceObject(Section);
+            return Status;
+        }
+        ASSERT(Status != STATUS_PENDING);
+
+        FileSizes.ValidDataLength = FileInfo.EndOfFile;
+        FileSizes.FileSize = FileInfo.EndOfFile;
+    }
+    DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
+
+    /*
     * FIXME: Revise this once a locking order for file size changes is
     * decided
+    *
+    * We're handed down a maximum size in every case.  Should we still check at all?
+    */
+    if (UMaximumSize != NULL && UMaximumSize->QuadPart)
+    {
+        DPRINT("Taking maximum %x\n", UMaximumSize->LowPart);
+        MaximumSize.QuadPart = UMaximumSize->QuadPart;
+    }
+    else
+    {
+        DPRINT("Got file size %08x%08x\n",
+               FileSizes.FileSize.u.HighPart,
+               FileSizes.FileSize.u.LowPart);
+
+        MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
+    }
+
+    /* Mapping zero-sized files isn't allowed. */
+    if (MaximumSize.QuadPart == 0)
+    {
+        DPRINT("Zero size file\n");
+        ObDereferenceObject(Section);
+        return STATUS_FILE_INVALID;
+    }
+
+    Segment = ExAllocatePoolWithTag(NonPagedPool,
+                                    sizeof(MM_SECTION_SEGMENT),
+                                    TAG_MM_SECTION_SEGMENT);
+    if (Segment == NULL)
+    {
+        DPRINT("Failed: STATUS_NO_MEMORY\n");
+        ObDereferenceObject(Section);
+        return STATUS_NO_MEMORY;
+    }
+
+    DPRINT("Zeroing %x\n", Segment);
+    RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT));
+    ExInitializeFastMutex(&Segment->Lock);
+
+    Segment->ReferenceCount = 1;
+    Segment->Locked = TRUE;
+    RtlZeroMemory(&Segment->Image, sizeof(Segment->Image));
+    Section->Segment = Segment;
+
+    KeAcquireSpinLock(&FileObject->IrpListLock, &OldIrql);
+    /*
+    * If this file hasn't been mapped as a data file before then allocate a
+    * section segment to describe the data file mapping
     */
-   if (UMaximumSize != NULL)
-   {
-          MaximumSize.QuadPart = UMaximumSize->QuadPart;
-   }
-   else
-   {
-          DPRINT("Got file size %08x%08x\n", FileSizes.FileSize.u.HighPart, FileSizes.FileSize.u.LowPart);
-          MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
-   }
-
-   Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_CACHE_SECTION_SEGMENT),
-                                  TAG_MM_SECTION_SEGMENT);
-   if (Segment == NULL)
-   {
-       return(STATUS_NO_MEMORY);
-   }
-
-   ExInitializeFastMutex(&Segment->Lock);
-
-   Segment->ReferenceCount = 1;
-   
-   /*
-       * Set the lock before assigning the segment to the file object
-       */
-   ExAcquireFastMutex(&Segment->Lock);
-   
-   DPRINT("Filling out Segment info (No previous data section)\n");
-   ObReferenceObject(FileObject);
-   Segment->FileObject = FileObject;
-   Segment->Protection = SectionPageProtection;
-   Segment->Flags = MM_DATAFILE_SEGMENT;
-   memset(&Segment->Image, 0, sizeof(Segment->Image));
-   Segment->WriteCopy = FALSE;
-   if (AllocationAttributes & SEC_RESERVE)
-   {
-          Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
-   }
-   else
-   {
-          Segment->RawLength = MaximumSize;
-          Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
-   }
-
-   MiInitializeSectionPageTable(Segment);
-   MmUnlockCacheSectionSegment(Segment);
-
-   /* Extend file if section is longer */
-   DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
-                 MaximumSize.u.HighPart, MaximumSize.u.LowPart,
-                 FileSizes.ValidDataLength.u.HighPart, FileSizes.ValidDataLength.u.LowPart);
-   if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
-   {
-          DPRINT("Changing file size to %08x%08x, segment %x\n", MaximumSize.u.HighPart, MaximumSize.u.LowPart, Segment);
-          Status = IoSetInformation(FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), &MaximumSize);
-          DPRINT("Change: Status %x\n", Status);
-          if (!NT_SUCCESS(Status))
-          {
-                  DPRINT("Could not expand section\n");
-                  return Status;
-          }
-   }
-
-   DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
-
-   *SegmentObject = Segment;
-
-   return(STATUS_SUCCESS);
+    if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
+    {
+        FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
+        KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
+
+        /*
+        * Set the lock before assigning the segment to the file object
+        */
+        ExAcquireFastMutex(&Segment->Lock);
+
+        DPRINT("Filling out Segment info (No previous data section)\n");
+        ObReferenceObject(FileObject);
+        Segment->FileObject = FileObject;
+        Segment->Protection = SectionPageProtection;
+        Segment->Flags = MM_DATAFILE_SEGMENT;
+        memset(&Segment->Image, 0, sizeof(Segment->Image));
+        Segment->WriteCopy = FALSE;
+
+        if (AllocationAttributes & SEC_RESERVE)
+        {
+            Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
+        }
+        else
+        {
+            Segment->RawLength.QuadPart = MaximumSize.QuadPart;
+            Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
+        }
+        MiInitializeSectionPageTable(Segment);
+        InsertHeadList(&MiSegmentList, &Segment->ListOfSegments);
+    }
+    else
+    {
+        KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
+        DPRINTC("Free Segment %x\n", Segment);
+        ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT);
+
+        DPRINT("Filling out Segment info (previous data section)\n");
+
+        /*
+        * If the file is already mapped as a data file then we may need
+        * to extend it
+        */
+        Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->DataSectionObject;
+        Section->Segment = Segment;
+        (void)InterlockedIncrementUL(&Segment->ReferenceCount);
+
+        MmLockSectionSegment(Segment);
+
+        if (MaximumSize.QuadPart > Segment->RawLength.QuadPart &&
+            !(AllocationAttributes & SEC_RESERVE))
+        {
+            Segment->RawLength.QuadPart = MaximumSize.QuadPart;
+            Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
+        }
+    }
+
+    MmUnlockSectionSegment(Segment);
+
+    Section->MaximumSize.QuadPart = MaximumSize.QuadPart;
+
+    /* Extend file if section is longer */
+    DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
+           MaximumSize.u.HighPart,
+           MaximumSize.u.LowPart,
+           FileSizes.ValidDataLength.u.HighPart,
+           FileSizes.ValidDataLength.u.LowPart);
+    if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
+    {
+        DPRINT("Changing file size to %08x%08x, segment %x\n",
+               MaximumSize.u.HighPart,
+               MaximumSize.u.LowPart,
+               Segment);
+
+        Status = IoSetInformation(FileObject,
+                                  FileEndOfFileInformation,
+                                  sizeof(LARGE_INTEGER),
+                                  &MaximumSize);
+
+        DPRINT("Change: Status %x\n", Status);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("Could not expand section\n");
+            ObDereferenceObject(Section);
+            return Status;
+        }
+    }
+
+    DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
+
+    *SectionObject = Section;
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
 NTAPI
-_MiMapViewOfSegment
-(PMMSUPPORT AddressSpace,
- PMM_CACHE_SECTION_SEGMENT Segment,
- PVOID* BaseAddress,
- SIZE_T ViewSize,
- ULONG Protect,
- PLARGE_INTEGER ViewOffset,
- ULONG AllocationType,
- const char *file,
- int line)
+_MiMapViewOfSegment(PMMSUPPORT AddressSpace,
+                    PMM_SECTION_SEGMENT Segment,
+                    PVOID* BaseAddress,
+                    SIZE_T ViewSize,
+                    ULONG Protect,
+                    PLARGE_INTEGER ViewOffset,
+                    ULONG AllocationType,
+                    const char *file,
+                    int line)
 {
-   PMEMORY_AREA MArea;
-   NTSTATUS Status;
-   PHYSICAL_ADDRESS BoundaryAddressMultiple;
-
-   BoundaryAddressMultiple.QuadPart = 0;
-
-   Status = MmCreateMemoryArea
-          (AddressSpace,
-               MEMORY_AREA_CACHE,
-               BaseAddress,
-               ViewSize,
-               Protect,
-               &MArea,
-               FALSE,
-               AllocationType,
-               BoundaryAddressMultiple);
-
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
-                         (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
-      return(Status);
-   }
-
-   DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n", MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, Segment, ViewOffset ? ViewOffset->LowPart : 0, ViewSize, Segment->FileObject ? &Segment->FileObject->FileName : NULL, file, line);
-
-   MArea->Data.CacheData.Segment = Segment;
-   if (ViewOffset)
-          MArea->Data.CacheData.ViewOffset = *ViewOffset;
-   else
-          MArea->Data.CacheData.ViewOffset.QuadPart = 0;
+    PMEMORY_AREA MArea;
+    NTSTATUS Status;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
+    BoundaryAddressMultiple.QuadPart = 0;
+
+    Status = MmCreateMemoryArea(AddressSpace,
+                                MEMORY_AREA_CACHE,
+                                BaseAddress,
+                                ViewSize,
+                                Protect,
+                                &MArea,
+                                FALSE,
+                                AllocationType,
+                                BoundaryAddressMultiple);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
+               (*BaseAddress),
+               (char*)(*BaseAddress) + ViewSize,
+               Status);
+
+        return Status;
+    }
+
+    DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n",
+            MmGetAddressSpaceOwner(AddressSpace),
+            *BaseAddress,
+            Segment,
+            ViewOffset ? ViewOffset->LowPart : 0,
+            ViewSize,
+            Segment->FileObject ? &Segment->FileObject->FileName : NULL,
+            file,
+            line);
+
+    MArea->Data.SectionData.Segment = Segment;
+    if (ViewOffset)
+        MArea->Data.SectionData.ViewOffset = *ViewOffset;
+    else
+        MArea->Data.SectionData.ViewOffset.QuadPart = 0;
 
 #if 0
-   MArea->NotPresent = MmNotPresentFaultPageFile;
-   MArea->AccessFault = MiCowSectionPage;
-   MArea->PageOut = MmPageOutPageFileView;
+    MArea->NotPresent = MmNotPresentFaultPageFile;
+    MArea->AccessFault = MiCowSectionPage;
+    MArea->PageOut = MmPageOutPageFileView;
 #endif
 
-   DPRINTC
-          ("MiMapViewOfSegment(P %x, A %x, T %x)\n",
-               MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, MArea->Type);
+    MmInitializeRegion(&MArea->Data.SectionData.RegionListHead,
+                       ViewSize,
+                       0,
+                       Protect);
+
+    DPRINTC("MiMapViewOfSegment(P %x, A %x, T %x)\n",
+            MmGetAddressSpaceOwner(AddressSpace),
+            *BaseAddress,
+            MArea->Type);
 
-   return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
+/*
+
+Completely remove the page at FileOffset in Segment.  The page must not
+be mapped.
+
+*/
+
 VOID
 NTAPI
-MiFreeSegmentPage
-(PMM_CACHE_SECTION_SEGMENT Segment,
- PLARGE_INTEGER FileOffset)
+MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment,
+                  PLARGE_INTEGER FileOffset)
 {
-       ULONG Entry;
-       PFILE_OBJECT FileObject = Segment->FileObject;
-
-       Entry = MiGetPageEntryCacheSectionSegment(Segment, FileOffset);
-       DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
-                       Segment, FileOffset->HighPart, FileOffset->LowPart, Entry);
-
-       if (Entry && !IS_SWAP_FROM_SSE(Entry))
-       {
-               // The segment is carrying a dirty page.
-               PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
-               if (IS_DIRTY_SSE(Entry) && FileObject)
-               {
-                       DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n", Segment, &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart);
-                       MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
-               }
-               DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n", OldPage, FileOffset->LowPart, Segment, MmGetReferenceCountPage(OldPage), Entry, IS_DIRTY_SSE(Entry) ? "true" : "false");
-
-               MiSetPageEntryCacheSectionSegment(Segment, FileOffset, 0);
-               MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
-       }
-       else if (IS_SWAP_FROM_SSE(Entry))
-       {
-               DPRINT("Free swap\n");
-               MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
-       }
-
-       DPRINT("Done\n");
+    ULONG_PTR Entry;
+    PFILE_OBJECT FileObject = Segment->FileObject;
+
+    Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
+    DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
+            Segment,
+            FileOffset->HighPart,
+            FileOffset->LowPart,
+            Entry);
+
+    if (Entry && !IS_SWAP_FROM_SSE(Entry))
+    {
+        // The segment is carrying a dirty page.
+        PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
+        if (IS_DIRTY_SSE(Entry) && FileObject)
+        {
+            DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n",
+                   Segment,
+                   &FileObject->FileName,
+                   FileOffset->u.HighPart,
+                   FileOffset->u.LowPart);
+
+            MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
+        }
+        DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n",
+                OldPage,
+                FileOffset->LowPart,
+                Segment,
+                MmGetReferenceCountPage(OldPage),
+                Entry,
+                IS_DIRTY_SSE(Entry) ? "true" : "false");
+
+        MmSetPageEntrySectionSegment(Segment, FileOffset, 0);
+        MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
+    }
+    else if (IS_SWAP_FROM_SSE(Entry))
+    {
+        DPRINT("Free swap\n");
+        MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
+    }
+
+    DPRINT("Done\n");
 }
 
 VOID
-MmFreeCacheSectionPage
-(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
- PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
+MmFreeCacheSectionPage(PVOID Context,
+                       MEMORY_AREA* MemoryArea,
+                       PVOID Address,
+                       PFN_NUMBER Page,
+                       SWAPENTRY SwapEntry,
+                       BOOLEAN Dirty)
 {
-   ULONG Entry;
-   PVOID *ContextData = Context;
-   PMMSUPPORT AddressSpace;
-   PEPROCESS Process;
-   PMM_CACHE_SECTION_SEGMENT Segment;
-   LARGE_INTEGER Offset;
-
-   DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n", MmGetAddressSpaceOwner(ContextData[0]), Address, Page, SwapEntry, Dirty);
-
-   AddressSpace = ContextData[0];
-   Process = MmGetAddressSpaceOwner(AddressSpace);
-   Address = (PVOID)PAGE_ROUND_DOWN(Address);
-   Segment = ContextData[1];
-   Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
-          MemoryArea->Data.CacheData.ViewOffset.QuadPart;
-
-   Entry = MiGetPageEntryCacheSectionSegment(Segment, &Offset);
-
-   if (Page)
-   {
-          DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
-          MmSetSavedSwapEntryPage(Page, 0);
-          MmDeleteRmap(Page, Process, Address);
-          MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
-          MmReleasePageMemoryConsumer(MC_CACHE, Page);
-   }
-   if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
-   {
-          DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
-          MiSetPageEntryCacheSectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
-   }
-   else if (SwapEntry != 0)
-   {
-      MmFreeSwapPage(SwapEntry);
-   }
+    ULONG_PTR Entry;
+    PVOID *ContextData = Context;
+    PMMSUPPORT AddressSpace;
+    PEPROCESS Process;
+    PMM_SECTION_SEGMENT Segment;
+    LARGE_INTEGER Offset;
+
+    DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n",
+           MmGetAddressSpaceOwner(ContextData[0]),
+           Address,
+           Page,
+           SwapEntry,
+           Dirty);
+
+    AddressSpace = ContextData[0];
+    Process = MmGetAddressSpaceOwner(AddressSpace);
+    Address = (PVOID)PAGE_ROUND_DOWN(Address);
+    Segment = ContextData[1];
+    Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
+                      MemoryArea->Data.SectionData.ViewOffset.QuadPart;
+
+    Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
+
+    if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
+    {
+        DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
+        MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
+    }
+    if (Page)
+    {
+        DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
+        MmSetSavedSwapEntryPage(Page, 0);
+        MmDeleteRmap(Page, Process, Address);
+        MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
+        MmReleasePageMemoryConsumer(MC_CACHE, Page);
+    }
+    if (SwapEntry != 0)
+    {
+        MmFreeSwapPage(SwapEntry);
+    }
 }
 
 NTSTATUS
 NTAPI
-MmUnmapViewOfCacheSegment
-(PMMSUPPORT AddressSpace,
- PVOID BaseAddress)
+MmUnmapViewOfCacheSegment(PMMSUPPORT AddressSpace,
+                          PVOID BaseAddress)
 {
-   PVOID Context[2];
-   PMEMORY_AREA MemoryArea;
-   PMM_CACHE_SECTION_SEGMENT Segment;
+    PVOID Context[2];
+    PMEMORY_AREA MemoryArea;
+    PMM_SECTION_SEGMENT Segment;
+
+    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
+    if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
+    {
+        ASSERT(MemoryArea);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    MemoryArea->DeleteInProgress = TRUE;
+    Segment = MemoryArea->Data.SectionData.Segment;
+    MemoryArea->Data.SectionData.Segment = NULL;
+
+    MmLockSectionSegment(Segment);
 
-   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
-   if (MemoryArea == NULL)
-   {
-         ASSERT(MemoryArea);
-      return(STATUS_UNSUCCESSFUL);
-   }
+    Context[0] = AddressSpace;
+    Context[1] = Segment;
 
-   MemoryArea->DeleteInProgress = TRUE;
-   Segment = MemoryArea->Data.CacheData.Segment;
-   MemoryArea->Data.CacheData.Segment = NULL;
-   
-   MmLockCacheSectionSegment(Segment);
+    DPRINT("MmFreeMemoryArea(%x,%x)\n",
+           MmGetAddressSpaceOwner(AddressSpace),
+           MemoryArea->StartingAddress);
 
-   Context[0] = AddressSpace;
-   Context[1] = Segment;
-   DPRINT("MmFreeMemoryArea(%x,%x)\n", MmGetAddressSpaceOwner(AddressSpace), MemoryArea->StartingAddress);
-   MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
+    MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
 
-   MmUnlockCacheSectionSegment(Segment);
+    MmUnlockSectionSegment(Segment);
 
-   DPRINTC("MiUnmapViewOfSegment %x %x %x\n", MmGetAddressSpaceOwner(AddressSpace), BaseAddress, Segment);
+    DPRINTC("MiUnmapViewOfSegment %x %x %x\n",
+            MmGetAddressSpaceOwner(AddressSpace),
+            BaseAddress,
+            Segment);
 
-   return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
 NTAPI
-MmExtendCacheSection
-(PMM_CACHE_SECTION_SEGMENT Segment,
- PLARGE_INTEGER NewSize,
- BOOLEAN ExtendFile)
+MmExtendCacheSection(PROS_SECTION_OBJECT Section,
+                     PLARGE_INTEGER NewSize,
+                     BOOLEAN ExtendFile)
 {
-       LARGE_INTEGER OldSize;
-       DPRINT("Extend Segment %x\n", Segment);
-
-       MmLockCacheSectionSegment(Segment);
-       OldSize.QuadPart = Segment->RawLength.QuadPart;
-       MmUnlockCacheSectionSegment(Segment);
-
-       DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
-                  OldSize.u.HighPart, OldSize.u.LowPart,
-                  NewSize->u.HighPart, NewSize->u.LowPart);
-
-       if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
-       {
-               NTSTATUS Status;
-               Status = IoSetInformation(Segment->FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), NewSize);
-               if (!NT_SUCCESS(Status)) return Status;
-       }
-
-       MmLockCacheSectionSegment(Segment);
-       Segment->RawLength.QuadPart = NewSize->QuadPart;
-       Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, PAGE_ROUND_UP(Segment->RawLength.LowPart));
-       MmUnlockCacheSectionSegment(Segment);
-       return STATUS_SUCCESS;
+    LARGE_INTEGER OldSize;
+    PMM_SECTION_SEGMENT Segment = Section->Segment;
+    DPRINT("Extend Segment %x\n", Segment);
+
+    MmLockSectionSegment(Segment);
+    OldSize.QuadPart = Segment->RawLength.QuadPart;
+    MmUnlockSectionSegment(Segment);
+
+    DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
+           OldSize.u.HighPart, OldSize.u.LowPart,
+           NewSize->u.HighPart, NewSize->u.LowPart);
+
+    if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
+    {
+        NTSTATUS Status;
+
+        Status = IoSetInformation(Segment->FileObject,
+                                  FileEndOfFileInformation,
+                                  sizeof(LARGE_INTEGER),
+                                  NewSize);
+
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    MmLockSectionSegment(Segment);
+    Segment->RawLength.QuadPart = NewSize->QuadPart;
+    Segment->Length.QuadPart = MAX(Segment->Length.QuadPart,
+                                   (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart));
+    MmUnlockSectionSegment(Segment);
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS 
+NTSTATUS
 NTAPI
-MmMapCacheViewInSystemSpaceAtOffset
-(IN PMM_CACHE_SECTION_SEGMENT Segment,
- OUT PVOID *MappedBase,
- PLARGE_INTEGER FileOffset,
- IN OUT PULONG ViewSize)
+MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment,
+                                    OUT PVOID *MappedBase,
+                                    PLARGE_INTEGER FileOffset,
+                                    IN OUT PULONG ViewSize)
 {
     PMMSUPPORT AddressSpace;
     NTSTATUS Status;
-    
-    DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n", FileOffset->HighPart, FileOffset->LowPart);
-    
+
+    DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n",
+           FileOffset->HighPart,
+           FileOffset->LowPart);
+
     AddressSpace = MmGetKernelAddressSpace();
-    
+
     MmLockAddressSpace(AddressSpace);
-    MmLockCacheSectionSegment(Segment);
-    
-    Status = MiMapViewOfSegment
-               (AddressSpace,
-                Segment,
-                MappedBase,
-                *ViewSize,
-                PAGE_READWRITE,
-                FileOffset,
-                0);
-    
-    MmUnlockCacheSectionSegment(Segment);
+    MmLockSectionSegment(Segment);
+
+    Status = MiMapViewOfSegment(AddressSpace,
+                                Segment,
+                                MappedBase,
+                                *ViewSize,
+                                PAGE_READWRITE,
+                                FileOffset,
+                                0);
+
+    MmUnlockSectionSegment(Segment);
     MmUnlockAddressSpace(AddressSpace);
-    
+
     return Status;
 }
 
@@ -695,16 +912,16 @@ MmMapCacheViewInSystemSpaceAtOffset
 NTSTATUS NTAPI
 MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
 {
-   PMMSUPPORT AddressSpace;
-   NTSTATUS Status;
+    PMMSUPPORT AddressSpace;
+    NTSTATUS Status;
 
-   DPRINT("MmUnmapViewInSystemSpace() called\n");
+    DPRINT("MmUnmapViewInSystemSpace() called\n");
 
-   AddressSpace = MmGetKernelAddressSpace();
+    AddressSpace = MmGetKernelAddressSpace();
 
-   Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
+    Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
 
-   return Status;
+    return Status;
 }
 
 /* EOF */