- Lock always the address space if we changing the virtual mapping. 
  This is necessary because we can create or remove a page table.
- If we unmap a section, we have to wait for all pending pageops 
  for the section within the current process. We do this by waiting 
  for all pageops for the section.
Modified: trunk/reactos/ntoskrnl/mm/section.c

Modified: trunk/reactos/ntoskrnl/mm/section.c
--- trunk/reactos/ntoskrnl/mm/section.c	2005-10-29 14:09:00 UTC (rev 18848)
+++ trunk/reactos/ntoskrnl/mm/section.c	2005-10-29 14:10:35 UTC (rev 18849)
@@ -1278,6 +1278,7 @@
     */
    MiCopyFromUserPage(NewPage, PAddress);
 
+   MmLockAddressSpace(AddressSpace);
    /*
     * Delete the old entry.
     */
@@ -1286,7 +1287,6 @@
    /*
     * Set the PTE to point to the new page
     */
-   MmLockAddressSpace(AddressSpace);
    Status = MmCreateVirtualMapping(AddressSpace->Process,
                                    Address,
                                    Region->Protect,
@@ -1298,7 +1298,6 @@
       KEBUGCHECK(0);
       return(Status);
    }
-   MmInsertRmap(NewPage, AddressSpace->Process, PAddress);
    if (!NT_SUCCESS(Status))
    {
       DbgPrint("Unable to create virtual mapping\n");
@@ -1314,6 +1313,7 @@
     * Unshare the old page.
     */
    MmDeleteRmap(OldPage, AddressSpace->Process, PAddress);
+   MmInsertRmap(NewPage, AddressSpace->Process, PAddress);
    MmLockSectionSegment(Segment);
    MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
    MmUnlockSectionSegment(Segment);
@@ -1332,6 +1332,11 @@
    PFN_TYPE Page;
 
    PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
+   if (Process)
+   {
+      MmLockAddressSpace(&Process->AddressSpace);
+   }
+
    MmDeleteVirtualMapping(Process,
                           Address,
                           FALSE,
@@ -1343,14 +1348,21 @@
    }
    if (!PageOutContext->Private)
    {
+      MmLockSectionSegment(PageOutContext->Segment);
       MmUnsharePageEntrySectionSegment(PageOutContext->Section,
                                        PageOutContext->Segment,
                                        PageOutContext->Offset,
                                        PageOutContext->WasDirty,
                                        TRUE);
+      MmUnlockSectionSegment(PageOutContext->Segment);
    }
-   else
+   if (Process)
    {
+      MmUnlockAddressSpace(&Process->AddressSpace);
+   }
+   
+   if (PageOutContext->Private)
+   {
       MmReleasePageMemoryConsumer(MC_USER, Page);
    }
 
@@ -1561,9 +1573,11 @@
    else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
    {
       MmSetSavedSwapEntryPage(Page, 0);
+      MmLockAddressSpace(AddressSpace);
       Status = MmCreatePageFileMapping(AddressSpace->Process,
                                        Address,
                                        SwapEntry);
+      MmUnlockAddressSpace(AddressSpace);
       if (!NT_SUCCESS(Status))
       {
          KEBUGCHECK(0);
@@ -1583,7 +1597,7 @@
       if (SwapEntry == 0)
       {
          MmShowOutOfSpaceMessagePagingFile();
-
+         MmLockAddressSpace(AddressSpace);
          /*
           * For private pages restore the old mappings.
           */
@@ -1618,6 +1632,7 @@
             Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
             MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
          }
+         MmUnlockAddressSpace(AddressSpace);
          PageOp->Status = STATUS_UNSUCCESSFUL;
          MmspCompleteAndReleasePageOp(PageOp);
          return(STATUS_PAGEFILE_QUOTA);
@@ -1636,6 +1651,7 @@
        * As above: undo our actions.
        * FIXME: Also free the swap page.
        */
+      MmLockAddressSpace(AddressSpace);
       if (Context.Private)
       {
          Status = MmCreateVirtualMapping(AddressSpace->Process,
@@ -1662,6 +1678,7 @@
          Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
          MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
       }
+      MmUnlockAddressSpace(AddressSpace);
       PageOp->Status = STATUS_UNSUCCESSFUL;
       MmspCompleteAndReleasePageOp(PageOp);
       return(STATUS_UNSUCCESSFUL);
@@ -1684,9 +1701,11 @@
 
    if (Context.Private)
    {
+      MmLockAddressSpace(AddressSpace);
       Status = MmCreatePageFileMapping(AddressSpace->Process,
                                        Address,
                                        SwapEntry);
+      MmUnlockAddressSpace(AddressSpace);
       if (!NT_SUCCESS(Status))
       {
          KEBUGCHECK(0);
@@ -3797,7 +3816,7 @@
    }
 }
 
-NTSTATUS
+STATIC NTSTATUS
 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
                      PVOID BaseAddress)
 {
@@ -3860,6 +3879,8 @@
    PMEMORY_AREA MemoryArea;
    PMADDRESS_SPACE AddressSpace;
    PSECTION_OBJECT Section;
+   PMM_PAGEOP PageOp;
+   ULONG_PTR Offset;
 
    DPRINT("Opening memory area Process %x BaseAddress %x\n",
           Process, BaseAddress);
@@ -3867,15 +3888,53 @@
    ASSERT(Process);
 
    AddressSpace = &Process->AddressSpace;
+   
+   MmLockAddressSpace(AddressSpace);
    MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
                                             BaseAddress);
    if (MemoryArea == NULL ||
        MemoryArea->Type != MEMORY_AREA_SECTION_VIEW ||
        MemoryArea->DeleteInProgress)
    {
+      MmUnlockAddressSpace(AddressSpace);
       return STATUS_NOT_MAPPED_VIEW;
    }
 
+   MemoryArea->DeleteInProgress = TRUE;
+
+   while (MemoryArea->PageOpCount)
+   {
+      Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
+
+      while (Offset)
+      {
+         Offset -= PAGE_SIZE;
+         PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
+                                   MemoryArea->Data.SectionData.Segment,
+                                   Offset + MemoryArea->Data.SectionData.ViewOffset);
+         if (PageOp)
+         {
+            MmUnlockAddressSpace(AddressSpace);
+            Status = MmspWaitForPageOpCompletionEvent(PageOp);
+            if (Status != STATUS_SUCCESS)
+            {
+               DPRINT1("Failed to wait for page op, status = %x\n", Status);
+               KEBUGCHECK(0);
+            }
+            MmLockAddressSpace(AddressSpace);
+            MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+                                                     BaseAddress);
+            if (MemoryArea == NULL ||
+                MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
+            {
+               MmUnlockAddressSpace(AddressSpace);
+               return STATUS_NOT_MAPPED_VIEW;
+            }
+            break;
+         }
+      }
+   }
+
    Section = MemoryArea->Data.SectionData.Section;
 
    if (Section->AllocationAttributes & SEC_IMAGE)
@@ -3925,6 +3984,7 @@
    {
       Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
    }
+   MmUnlockAddressSpace(AddressSpace);
    return(STATUS_SUCCESS);
 }
 
@@ -3970,9 +4030,7 @@
       return(Status);
    }
 
-   MmLockAddressSpace(&Process->AddressSpace);
    Status = MmUnmapViewOfSection(Process, BaseAddress);
-   MmUnlockAddressSpace(&Process->AddressSpace);
 
    ObDereferenceObject(Process);