[NTOSKRNL]: Cleanup MmCreateArm3Section a little bit to handle file-backed sections...
authorAlex Ionescu <aionescu@gmail.com>
Fri, 24 Aug 2012 17:17:36 +0000 (17:17 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Fri, 24 Aug 2012 17:17:36 +0000 (17:17 +0000)
[NTOSKRNL]: Remove an ASSERT(FALSE) that was only there for testing.
[NTOSKRNL]: Enable richard's ARM3 section code unconditionally for all non-file backed sections. Works4me. Let's see what Testbot says.

svn path=/trunk/; revision=57155

reactos/ntoskrnl/mm/ARM3/pfnlist.c
reactos/ntoskrnl/mm/ARM3/section.c
reactos/ntoskrnl/mm/section.c

index cd633cb..317f883 100644 (file)
@@ -1335,7 +1335,6 @@ MiDecrementReferenceCount(IN PMMPFN Pfn1,
     }
 
     /* Check to see which list this page should go into */
-    ASSERT(FALSE);
     if (Pfn1->u3.e1.Modified == 1)
     {
         /* Push it into the modified page list */
index f436639..dfa2dfe 100644 (file)
@@ -894,10 +894,10 @@ MiSessionCommitPageTables(IN PVOID StartVa,
     ASSERT(ActualPages <= PageCount);
 
     /* Release the working set lock */
-//  MiUnlockWorkingSet(PsGetCurrentThread(), 
+//  MiUnlockWorkingSet(PsGetCurrentThread(),
 //                     &MmSessionSpace->GlobalVirtualAddress->Vm);
 
-    
+
     /* If we did at least one page... */
     if (ActualPages)
     {
@@ -974,7 +974,7 @@ MiMapViewInSystemSpace(IN PVOID Section,
     {
         /* Create the PDEs needed for this mapping */
         Status = MiSessionCommitPageTables(Base,
-                                           (PVOID)((ULONG_PTR)Base + 
+                                           (PVOID)((ULONG_PTR)Base +
                                            Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE));
         NT_ASSERT(NT_SUCCESS(Status));
     }
@@ -1243,6 +1243,37 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
     return STATUS_SUCCESS;
 }
 
+VOID
+NTAPI
+MiSubsectionConsistent(IN PSUBSECTION Subsection)
+{
+    /* ReactOS only supports systems with 4K pages and 4K sectors */
+    ASSERT(Subsection->u.SubsectionFlags.SectorEndOffset == 0);
+
+    /* Therefore, then number of PTEs should be equal to the number of sectors */
+    if (Subsection->NumberOfFullSectors != Subsection->PtesInSubsection)
+    {
+        /* Break and warn if this is inconsistent */
+        DPRINT1("Mm: Subsection inconsistent (%x vs %x)\n",
+                Subsection->NumberOfFullSectors, Subsection->PtesInSubsection);
+        DbgBreakPoint();
+    }
+}
+
+NTSTATUS
+NTAPI
+MiCreateDataFileMap(IN PFILE_OBJECT File,
+                    OUT PSEGMENT *Segment,
+                    IN PSIZE_T MaximumSize,
+                    IN ULONG SectionPageProtection,
+                    IN ULONG AllocationAttributes,
+                    IN ULONG IgnoreFileSizing)
+{
+    /* Not yet implemented */
+    ASSERT(FALSE);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 NTSTATUS
 NTAPI
 MiCreatePagingFileMap(OUT PSEGMENT *Segment,
@@ -2048,15 +2079,15 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
     SECTION Section;
     PSECTION NewSection;
     PSUBSECTION Subsection;
-    PSEGMENT NewSegment;
+    PSEGMENT NewSegment, Segment;
     NTSTATUS Status;
     PCONTROL_AREA ControlArea;
-    ULONG ProtectionMask;
-
-    /* ARM3 does not yet support this */
-    ASSERT(FileHandle == NULL);
-    ASSERT(FileObject == NULL);
-    ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
+    ULONG ProtectionMask, ControlAreaSize, Size, NonPagedCharge, PagedCharge;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    BOOLEAN FileLock = FALSE, KernelCall = FALSE;
+    KIRQL OldIrql;
+    PFILE_OBJECT File;
+    PVOID PreviousSectionPointer;
 
     /* Make the same sanity checks that the Nt interface should've validated */
     ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
@@ -2079,53 +2110,229 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
     ProtectionMask = MiMakeProtectionMask(SectionPageProtection);
     if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION;
 
-    /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
-    if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
+    /* Check if this is going to be a data or image backed file section */
+    if ((FileHandle) || (FileObject))
+    {
+        /* These cannot be mapped with large pages */
+        if (AllocationAttributes & SEC_LARGE_PAGES) return STATUS_INVALID_PARAMETER_6;
 
-    /* So this must be a pagefile-backed section, create the mappings needed */
-    Status = MiCreatePagingFileMap(&NewSegment,
-                                   (PSIZE_T)InputMaximumSize,
-                                   ProtectionMask,
-                                   AllocationAttributes);
-    ASSERT(NT_SUCCESS(Status));
-    ASSERT(NewSegment != NULL);
+        /* For now, only support the mechanism through a file handle */
+        ASSERT(FileObject == NULL);
+
+        /* Reference the file handle to get the object */
+        Status = ObReferenceObjectByHandle(FileHandle,
+                                           MmMakeFileAccess[ProtectionMask],
+                                           IoFileObjectType,
+                                           PreviousMode,
+                                           (PVOID*)&File,
+                                           NULL);
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Make sure Cc has been doing its job */
+        if (!File->SectionObjectPointer)
+        {
+            /* This is not a valid file system-based file, fail */
+            ObDereferenceObject(File);
+            return STATUS_INVALID_FILE_FOR_SECTION;
+        }
+
+        /* Image-file backed sections are not yet supported */
+        ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+
+        /* Compute the size of the control area, and allocate it */
+        ControlAreaSize = sizeof(CONTROL_AREA) + sizeof(MSUBSECTION);
+        ControlArea = ExAllocatePoolWithTag(NonPagedPool, ControlAreaSize, 'aCmM');
+        if (!ControlArea)
+        {
+            ObDereferenceObject(File);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Zero it out */
+        RtlZeroMemory(ControlArea, ControlAreaSize);
+
+        /* Did we get a handle, or an object? */
+        if (FileHandle)
+        {
+            /* We got a file handle so we have to lock down the file */
+#if 0
+            Status = FsRtlAcquireToCreateMappedSection(File, SectionPageProtection);
+            if (!NT_SUCCESS(Status))
+            {
+                ExFreePool(ControlArea);
+                ObDereferenceObject(File);
+                return Status;
+            }
+#else
+            /* ReactOS doesn't support this API yet, so do nothing */
+            Status = STATUS_SUCCESS;
+#endif
+            /* Update the top-level IRP so that drivers know what's happening */
+            IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
+            FileLock = TRUE;
+        }
+
+        /* Lock the PFN database while we play with the section pointers */
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        /* Image-file backed sections are not yet supported */
+        ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+
+        /* There should not already be a control area for this file */
+        ASSERT(File->SectionObjectPointer->DataSectionObject == NULL);
+        NewSegment = NULL;
+
+        /* Write down that this CA is being created, and set it */
+        ControlArea->u.Flags.BeingCreated = TRUE;
+        PreviousSectionPointer = File->SectionObjectPointer;
+        File->SectionObjectPointer->DataSectionObject = ControlArea;
+
+        /* We can release the PFN lock now */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+        /* We don't support previously-mapped file */
+        ASSERT(NewSegment == NULL);
+
+        /* Image-file backed sections are not yet supported */
+        ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+
+        /* So we always create a data file map */
+        Status = MiCreateDataFileMap(File,
+                                     &Segment,
+                                     (PSIZE_T)InputMaximumSize,
+                                     SectionPageProtection,
+                                     AllocationAttributes,
+                                     KernelCall);
+        ASSERT(PreviousSectionPointer == File->SectionObjectPointer);
+        ASSERT(NT_SUCCESS(Status));
+
+        /* Check if a maximum size was specified */
+        if (!InputMaximumSize->QuadPart)
+        {
+            /* Nope, use the segment size */
+            Section.SizeOfSection.QuadPart = (LONGLONG)Segment->SizeOfSegment;
+        }
+        else
+        {
+            /* Yep, use the entered size */
+            Section.SizeOfSection.QuadPart = InputMaximumSize->QuadPart;
+        }
+
+    }
+    else
+    {
+        /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */
+        if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
+
+        /* Not yet supported */
+        ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
+
+        /* So this must be a pagefile-backed section, create the mappings needed */
+        Status = MiCreatePagingFileMap(&NewSegment,
+                                       (PSIZE_T)InputMaximumSize,
+                                       ProtectionMask,
+                                       AllocationAttributes);
+        ASSERT(NT_SUCCESS(Status));
+
+        /* Set the size here, and read the control area */
+        Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
+        ControlArea = NewSegment->ControlArea;
+    }
+
+    /* Did we already have a segment? */
+    if (!NewSegment)
+    {
+        /* This must be the file path and we created a segment */
+        NewSegment = Segment;
+        ASSERT(File != NULL);
+
+        /* Acquire the PFN lock while we set control area flags */
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        /* We don't support this race condition yet, so assume no waiters */
+        ASSERT(ControlArea->WaitingForDeletion == NULL);
+        ControlArea->WaitingForDeletion = NULL;
+
+        /* Image-file backed sections are not yet supported, nor ROM images */
+        ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+        ASSERT(Segment->ControlArea->u.Flags.Rom == 0);
+
+        /* Take off the being created flag, and then release the lock */
+        ControlArea->u.Flags.BeingCreated = FALSE;
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    }
+
+    /* Check if we locked the file earlier */
+    if (FileLock)
+    {
+        /* Reset the top-level IRP and release the lock */
+        IoSetTopLevelIrp(NULL);
+        //FsRtlReleaseFile(File);
+        FileLock = FALSE;
+    }
 
     /* Set the initial section object data */
     Section.InitialPageProtection = SectionPageProtection;
-    Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
-    Section.Segment = NewSegment;
 
-    /* THe mapping created a control area and segment, save the flags */
-    ControlArea = NewSegment->ControlArea;
+    /* The mapping created a control area and segment, save the flags */
+    Section.Segment = NewSegment;
     Section.u.LongFlags = ControlArea->u.LongFlags;
 
-    /* ARM3 cannot support these right now, make sure they're not being set */
-    ASSERT(ControlArea->u.Flags.Image == 0);
-    ASSERT(ControlArea->FilePointer == NULL);
+    /* Check if this is a user-mode read-write non-image file mapping */
+    if (!(FileObject) &&
+        (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) &&
+        (ControlArea->u.Flags.Image == 0) &&
+        (ControlArea->FilePointer != NULL))
+    {
+        /* Add a reference and set the flag */
+        Section.u.Flags.UserWritable = 1;
+        InterlockedIncrement((PLONG)&ControlArea->WritableUserReferences);
+    }
+
+    /* Check for image mappings or page file mappings */
+    if ((ControlArea->u.Flags.Image == 1) || !(ControlArea->FilePointer))
+    {
+        /* Charge the segment size, and allocate a subsection */
+        PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE);
+        Size = sizeof(SUBSECTION);
+    }
+    else
+    {
+        /* Charge nothing, and allocate a mapped subsection */
+        PagedCharge = 0;
+        Size = sizeof(MSUBSECTION);
+    }
+
+    /* Check if this is a normal CA */
     ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
     ASSERT(ControlArea->u.Flags.Rom == 0);
-    ASSERT(ControlArea->u.Flags.WasPurged == 0);
 
-    /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
+    /* Charge only a CA, and the subsection is right after */
+    NonPagedCharge = sizeof(CONTROL_AREA);
     Subsection = (PSUBSECTION)(ControlArea + 1);
+
+    /* We only support single-subsection mappings */
+    NonPagedCharge += Size;
     ASSERT(Subsection->NextSubsection == NULL);
 
     /* Create the actual section object, with enough space for the prototype PTEs */
-    Status = ObCreateObject(ExGetPreviousMode(),
+    Status = ObCreateObject(PreviousMode,
                             MmSectionObjectType,
                             ObjectAttributes,
-                            ExGetPreviousMode(),
+                            PreviousMode,
                             NULL,
                             sizeof(SECTION),
-                            sizeof(SECTION) +
-                            NewSegment->TotalNumberOfPtes * sizeof(MMPTE),
-                            sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
+                            PagedCharge,
+                            NonPagedCharge,
                             (PVOID*)&NewSection);
     ASSERT(NT_SUCCESS(Status));
 
     /* Now copy the local section object from the stack into this new object */
     RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
     NewSection->Address.StartingVpn = 0;
+
+    /* For now, only user calls are supported */
+    ASSERT(KernelCall == FALSE);
     NewSection->u.Flags.UserReference = TRUE;
 
     /* Migrate the attribute into a flag */
@@ -2171,6 +2378,13 @@ MmCreateArm3Section(OUT PVOID *SectionObject,
         KeReleaseGuardedMutex(&MmSectionBasedMutex);
     }
 
+    /* Write down if this was a kernel call */
+    ControlArea->u.Flags.WasPurged |= KernelCall;
+    ASSERT(ControlArea->u.Flags.WasPurged == FALSE);
+
+    /* Make sure the segment and the section are the same size, or the section is smaller */
+    ASSERT(NewSection->SizeOfSection.QuadPart <= NewSection->Segment->SizeOfSegment);
+
     /* Return the object and the creation status */
     *SectionObject = (PVOID)NewSection;
     return Status;
index 802f767..4f0d75f 100644 (file)
@@ -4860,17 +4860,19 @@ MmCreateSection (OUT PVOID  * Section,
     PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
 
     /* Check if an ARM3 section is being created instead */
-    if (AllocationAttributes & 1)
+    if (!(AllocationAttributes & SEC_IMAGE) && (AllocationAttributes))
     {
-        DPRINT1("Creating ARM3 section\n");
-        return MmCreateArm3Section(Section,
-                                   DesiredAccess,
-                                   ObjectAttributes,
-                                   MaximumSize,
-                                   SectionPageProtection,
-                                   AllocationAttributes &~ 1,
-                                   FileHandle,
-                                   FileObject);
+        if (!(FileObject) && !(FileHandle))
+        {
+            return MmCreateArm3Section(Section,
+                                       DesiredAccess,
+                                       ObjectAttributes,
+                                       MaximumSize,
+                                       SectionPageProtection,
+                                       AllocationAttributes &~ 1,
+                                       FileHandle,
+                                       FileObject);
+        }
     }
 
     /*