Author: jgardou
Date: Sun Aug 28 19:53:27 2016
New Revision: 72493

URL: http://svn.reactos.org/svn/reactos?rev=72493&view=rev
Log:
[NTOS/MM]
 - Properly chain events when reading a page from disk, aka don't wait on 
events allocated on the stack of another thread
 - Use proper type pointers, compilers sometimes help making things right

Modified:
    trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c

Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c?rev=72493&r1=72492&r2=72493&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c   [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c   [iso-8859-1] Sun Aug 28 
19:53:27 2016
@@ -882,10 +882,10 @@
     PFN_NUMBER Page;
     NTSTATUS Status;
     MMPTE TempPte = *PointerPte;
-    KEVENT Event;
     PMMPFN Pfn1;
     ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
     ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
+    ULONG Protection = TempPte.u.Soft.Protection;
 
     /* Things we don't support yet */
     ASSERT(CurrentProcess > HYDRA_PROCESS);
@@ -911,16 +911,10 @@
     ASSERT(Pfn1->u1.Event == NULL);
     ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
     ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
-
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
-    Pfn1->u1.Event = &Event;
     Pfn1->u3.e1.ReadInProgress = 1;
 
     /* We must write the PTE now as the PFN lock will be released while 
performing the IO operation */
-    TempPte.u.Soft.Transition = 1;
-    TempPte.u.Soft.PageFileLow = 0;
-    TempPte.u.Soft.Prototype = 0;
-    TempPte.u.Trans.PageFrameNumber = Page;
+    MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
 
     MI_WRITE_INVALID_PTE(PointerPte, TempPte);
 
@@ -934,7 +928,6 @@
     *OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
 
     /* Nobody should have changed that while we were not looking */
-    ASSERT(Pfn1->u1.Event == &Event);
     ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
     ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
 
@@ -946,27 +939,29 @@
         Pfn1->u1.ReadStatus = Status;
     }
 
-    /* This is now a nice and normal PFN */
-    Pfn1->u1.Event = NULL;
+    /* And the PTE can finally be valid */
+    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
+    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
     Pfn1->u3.e1.ReadInProgress = 0;
-
-    /* And the PTE can finally be valid */
-    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, TempPte.u.Trans.Protection, 
Page);
-    MI_WRITE_VALID_PTE(PointerPte, TempPte);
-
-    /* Waiters gonna wait */
-    KeSetEvent(&Event, IO_NO_INCREMENT, FALSE);
+    /* Did someone start to wait on us while we proceeded ? */
+    if (Pfn1->u1.Event)
+    {
+        /* Tell them we're done */
+        KeSetEvent(Pfn1->u1.Event, IO_NO_INCREMENT, FALSE);
+    }
 
     return Status;
 }
 
 NTSTATUS
 NTAPI
-MiResolveTransitionFault(IN PVOID FaultingAddress,
+MiResolveTransitionFault(IN BOOLEAN StoreInstruction,
+                         IN PVOID FaultingAddress,
                          IN PMMPTE PointerPte,
                          IN PEPROCESS CurrentProcess,
                          IN KIRQL OldIrql,
-                         OUT PVOID *InPageBlock)
+                         OUT PKEVENT **InPageBlock)
 {
     PFN_NUMBER PageFrameIndex;
     PMMPFN Pfn1;
@@ -999,11 +994,11 @@
     ASSERT(Pfn1->u4.InPageError == 0);
 
     /* See if we should wait before terminating the fault */
-    if (Pfn1->u3.e1.ReadInProgress == 1)
-    {
-        DPRINT1("The page is currently being read!\n");
-        ASSERT(Pfn1->u1.Event != NULL);
-        *InPageBlock = Pfn1->u1.Event;
+    if ((Pfn1->u3.e1.ReadInProgress == 1)
+            || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
+    {
+        DPRINT1("The page is currently in a page transition !\n");
+        *InPageBlock = &Pfn1->u1.Event;
         if (PointerPte == Pfn1->PteAddress)
         {
             DPRINT1("And this if for this particular PTE.\n");
@@ -1061,7 +1056,7 @@
         }
     }
 
-    /* Build the transition PTE -- maybe a macro? */
+    /* Build the final PTE */
     ASSERT(PointerPte->u.Hard.Valid == 0);
     ASSERT(PointerPte->u.Trans.Prototype == 0);
     ASSERT(PointerPte->u.Trans.Transition == 1);
@@ -1107,7 +1102,7 @@
     PMMPFN Pfn1;
     PFN_NUMBER PageFrameIndex;
     NTSTATUS Status;
-    PVOID InPageBlock = NULL;
+    PKEVENT* InPageBlock = NULL;
     ULONG Protection;
 
     /* Must be called with an invalid, prototype PTE, with the PFN lock held */
@@ -1256,7 +1251,8 @@
     {
         /* Resolve the transition fault */
         ASSERT(OldIrql != MM_NOIRQL);
-        Status = MiResolveTransitionFault(Address,
+        Status = MiResolveTransitionFault(StoreInstruction,
+                                          Address,
                                           PointerProtoPte,
                                           Process,
                                           OldIrql,
@@ -1543,22 +1539,38 @@
     /* Is this a transition PTE */
     if (TempPte.u.Soft.Transition)
     {
-        PVOID InPageBlock = NULL;
+        PKEVENT* InPageBlock = NULL;
+        PKEVENT PreviousPageEvent;
+        KEVENT CurrentPageEvent;
+
         /* Lock the PFN database */
         LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
 
         /* Resolve */
-        Status = MiResolveTransitionFault(Address, PointerPte, Process, 
LockIrql, &InPageBlock);
+        Status = MiResolveTransitionFault(StoreInstruction, Address, 
PointerPte, Process, LockIrql, &InPageBlock);
 
         ASSERT(NT_SUCCESS(Status));
+
+        if (InPageBlock != NULL)
+        {
+            /* Another thread is reading or writing this page. Put us into the 
waiting queue. */
+            KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
+            PreviousPageEvent = *InPageBlock;
+            *InPageBlock = &CurrentPageEvent;
+        }
 
         /* And now release the lock and leave*/
         KeReleaseQueuedSpinLock(LockQueuePfnLock, LockIrql);
 
         if (InPageBlock != NULL)
         {
-            /* The page is being paged in by another process */
-            KeWaitForSingleObject(InPageBlock, WrPageIn, KernelMode, FALSE, 
NULL);
+            KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, 
FALSE, NULL);
+
+            /* Let's the chain go on */
+            if (PreviousPageEvent)
+            {
+                KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
+            }
         }
 
         ASSERT(OldIrql == KeGetCurrentIrql());


Reply via email to