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.…
==============================================================================
--- 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());