Author: ion
Date: Mon Sep 3 16:29:31 2012
New Revision: 57229
URL: http://svn.reactos.org/svn/reactos?rev=57229&view=rev
Log:
[NTOSKRNL]: Fix a stupid bug in MiProtectVirtualMemory which was causing empty PTEs whose protection was being set to remain zero PTEs, instead of demand-zero PTEs, but still acquire a page table reference. When they were later touched in the page fault code, and made into demand-zero PTEs, they'd get referenced again, thus Aleksey hacked away all the referencing code to work around this (causing PDEs to disappear...)
[NTOSKRNL]: Restore the page table reference counting mechanism, and put it in a macro to be cleaner. Also use macros for testing PD boundaries, instead of math-by-hand.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
trunk/reactos/ntoskrnl/mm/ARM3/section.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Mon Sep 3 16:29:31 2012
@@ -1619,6 +1619,41 @@
}
}
+FORCEINLINE
+VOID
+MiIncrementPageTableReferences(IN PVOID Address)
+{
+ PUSHORT RefCount;
+
+ RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
+
+ *RefCount += 1;
+ ASSERT(*RefCount <= PTE_PER_PAGE);
+}
+
+FORCEINLINE
+VOID
+MiDecrementPageTableReferences(IN PVOID Address)
+{
+ PUSHORT RefCount;
+
+ RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
+
+ *RefCount -= 1;
+ ASSERT(*RefCount < PTE_PER_PAGE);
+}
+
+FORCEINLINE
+USHORT
+MiQueryPageTableReferences(IN PVOID Address)
+{
+ PUSHORT RefCount;
+
+ RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
+
+ return *RefCount;
+}
+
BOOLEAN
NTAPI
MmArmInitSystem(
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] Mon Sep 3 16:29:31 2012
@@ -1684,8 +1684,7 @@
if (Address <= MM_HIGHEST_USER_ADDRESS)
{
/* Add an additional page table reference */
- MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
- ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
+ MiIncrementPageTableReferences(Address);
}
/* Did we get a prototype PTE back? */
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Mon Sep 3 16:29:31 2012
@@ -1821,7 +1821,6 @@
PMMPDE PointerPde;
PMMPFN Pfn1;
ULONG ProtectionMask, QuotaCharge = 0;
- PUSHORT UsedPageTableEntries;
PETHREAD Thread = PsGetCurrentThread();
PAGED_CODE();
@@ -1914,9 +1913,7 @@
// This used to be a zero PTE and it no longer is, so we must add a
// reference to the pagetable.
//
- UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))];
- (*UsedPageTableEntries)++;
- ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
+ MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
//
// Create the demand-zero prototype PTE
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Mon Sep 3 16:29:31 2012
@@ -589,10 +589,8 @@
TempPte = *PointerPte;
if (TempPte.u.Long)
{
- DPRINT("Decrement used PTEs by address: %lx\n", Va);
- (*UsedPageTableEntries)--;
+ *UsedPageTableEntries -= 1;
ASSERT((*UsedPageTableEntries) < PTE_COUNT);
- DPRINT("Refs: %lx\n", (*UsedPageTableEntries));
/* Check if the PTE is actually mapped in */
if (TempPte.u.Long & 0xFFFFFC01)
@@ -653,14 +651,10 @@
/* The PDE should still be valid at this point */
ASSERT(PointerPde->u.Hard.Valid == 1);
- DPRINT("Should check if handles for: %p are zero (PDE: %lx)\n", Va, PointerPde->u.Hard.PageFrameNumber);
- if (!(*UsedPageTableEntries))
- {
- DPRINT("They are!\n");
+ if (*UsedPageTableEntries == 0)
+ {
if (PointerPde->u.Long != 0)
{
- DPRINT("PDE active: %lx in %16s\n", PointerPde->u.Hard.PageFrameNumber, CurrentProcess->ImageFileName);
-
/* Delete the PTE proper */
MiDeletePte(PointerPde,
MiPteToAddress(PointerPde),
@@ -1880,7 +1874,6 @@
ULONG_PTR StartingAddress, EndingAddress;
PMMPTE PointerPde, PointerPte, LastPte;
MMPTE PteContents;
- //PUSHORT UsedPageTableEntries;
PMMPFN Pfn1;
ULONG ProtectionMask, OldProtect;
BOOLEAN Committed;
@@ -2050,24 +2043,23 @@
while (PointerPte <= LastPte)
{
/* Check if we've crossed a PDE boundary and make the new PDE valid too */
- if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0)
+ if (MiIsPteOnPdeBoundary(PointerPte))
{
PointerPde = MiAddressToPte(PointerPte);
MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
}
- /* Capture the PTE and see what we're dealing with */
+ /* Capture the PTE and check if it was empty */
PteContents = *PointerPte;
if (PteContents.u.Long == 0)
{
/* This used to be a zero PTE and it no longer is, so we must add a
reference to the pagetable. */
- //UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))];
- //(*UsedPageTableEntries)++;
- //ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
- DPRINT1("HACK: Not increasing UsedPageTableEntries count!\n");
- }
- else if (PteContents.u.Hard.Valid == 1)
+ MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
+ }
+
+ /* Check what kind of PTE we are dealing with */
+ if (PteContents.u.Hard.Valid == 1)
{
/* Get the PFN entry */
Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
@@ -2080,8 +2072,11 @@
(NewAccessProtection & PAGE_GUARD))
{
/* The page should be in the WS and we should make it transition now */
- UNIMPLEMENTED;
- //continue;
+ DPRINT1("Making valid page invalid is not yet supported!\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ /* Unlock the working set */
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
+ goto FailPath;
}
/* Write the protection mask and write it with a TLB flush */
@@ -2270,7 +2265,6 @@
ULONG PteCount = 0;
PMMPFN Pfn1;
MMPTE PteContents;
- PUSHORT UsedPageTableEntries;
PETHREAD CurrentThread = PsGetCurrentThread();
//
@@ -2292,7 +2286,7 @@
//
// Check if we've crossed a PDE boundary
//
- if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0)
+ if (MiIsPteOnPdeBoundary(PointerPte))
{
//
// Get the new PDE and flush the valid PTEs we had built up until
@@ -2383,9 +2377,7 @@
// This used to be a zero PTE and it no longer is, so we must add a
// reference to the pagetable.
//
- UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(StartingAddress)];
- (*UsedPageTableEntries)++;
- ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
+ MiIncrementPageTableReferences(StartingAddress);
//
// Next, we account for decommitted PTEs and make the PTE as such
@@ -3648,7 +3640,6 @@
PMEMORY_AREA MemoryArea;
PFN_NUMBER PageCount;
PMMVAD Vad, FoundVad;
- PUSHORT UsedPageTableEntries;
NTSTATUS Status;
PMMSUPPORT AddressSpace;
PVOID PBaseAddress;
@@ -4268,7 +4259,7 @@
//
// Have we crossed into a new page table?
//
- if (!(((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)))
+ if (MiIsPteOnPdeBoundary(PointerPte))
{
//
// Get the PDE and now make it valid too
@@ -4286,9 +4277,7 @@
// First increment the count of pages in the page table for this
// process
//
- UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))];
- (*UsedPageTableEntries)++;
- ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
+ MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
//
// And now write the invalid demand-zero PTE as requested
Author: ion
Date: Mon Sep 3 06:23:31 2012
New Revision: 57228
URL: http://svn.reactos.org/svn/reactos?rev=57228&view=rev
Log:
[NTOSKRNL]: Implement correct locking and unlocking of the working set, one of the biggest blunders in ARM3 so far.
[NTOSKRNL]: Implement MiDereferenceControlArea to avoid leaking CAs in failure cases.
Modified:
trunk/reactos/ntoskrnl/include/internal/mm.h
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
trunk/reactos/ntoskrnl/mm/ARM3/section.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] Mon Sep 3 06:23:31 2012
@@ -1718,17 +1718,13 @@
MmLockAddressSpace(PMMSUPPORT AddressSpace)
{
KeAcquireGuardedMutex(&CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock);
- //ASSERT(Thread->OwnsProcessAddressSpaceExclusive == 0);
- //Thread->OwnsProcessAddressSpaceExclusive = TRUE;
}
FORCEINLINE
VOID
MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
{
- //ASSERT(Thread->OwnsProcessAddressSpaceExclusive == 1);
KeReleaseGuardedMutex(&CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock);
- //Thread->OwnsProcessAddressSpaceExclusive = 0;
}
FORCEINLINE
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Mon Sep 3 06:23:31 2012
@@ -1041,6 +1041,14 @@
MI_WS_OWNER(IN PEPROCESS Process)
{
/* Check if this process is the owner, and that the thread owns the WS */
+ if (PsGetCurrentThread()->OwnsProcessWorkingSetExclusive == 0)
+ {
+ DPRINT1("Thread: %p is not an owner\n", PsGetCurrentThread());
+ }
+ if (KeGetCurrentThread()->ApcState.Process != &Process->Pcb)
+ {
+ DPRINT1("Current thread %p is attached to another process %p\n", PsGetCurrentThread(), Process);
+ }
return ((KeGetCurrentThread()->ApcState.Process == &Process->Pcb) &&
((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) ||
(PsGetCurrentThread()->OwnsProcessWorkingSetShared)));
@@ -1083,6 +1091,13 @@
IN PFN_NUMBER PageFrameIndex
);
+FORCEINLINE
+BOOLEAN
+MI_IS_WS_UNSAFE(IN PEPROCESS Process)
+{
+ return (Process->Vm.Flags.AcquiredUnsafe == TRUE);
+}
+
//
// Locks the working set for the given process
//
@@ -1099,12 +1114,57 @@
KeEnterGuardedRegion();
ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
- /* FIXME: Actually lock it (we can't because Vm is used by MAREAs) */
-
- /* FIXME: This also can't be checked because Vm is used by MAREAs) */
- //ASSERT(Process->Vm.Flags.AcquiredUnsafe == 0);
-
- /* Okay, now we can own it exclusively */
+ /* Lock the working set */
+ ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
+
+ /* Now claim that we own the lock */
+ ASSERT(!MI_IS_WS_UNSAFE(Process));
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+ Thread->OwnsProcessWorkingSetExclusive = TRUE;
+}
+
+FORCEINLINE
+VOID
+MiLockProcessWorkingSetShared(IN PEPROCESS Process,
+ IN PETHREAD Thread)
+{
+ /* Shouldn't already be owning the process working set */
+ ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+
+ /* Block APCs, make sure that still nothing is already held */
+ KeEnterGuardedRegion();
+ ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
+
+ /* Lock the working set */
+ ExAcquirePushLockShared(&Process->Vm.WorkingSetMutex);
+
+ /* Now claim that we own the lock */
+ ASSERT(!MI_IS_WS_UNSAFE(Process));
+ ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+ Thread->OwnsProcessWorkingSetShared = TRUE;
+}
+
+FORCEINLINE
+VOID
+MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process,
+ IN PETHREAD Thread)
+{
+ /* Shouldn't already be owning the process working set */
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
+
+ /* APCs must be blocked, make sure that still nothing is already held */
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
+ ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
+
+ /* Lock the working set */
+ ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
+
+ /* Now claim that we own the lock */
+ ASSERT(!MI_IS_WS_UNSAFE(Process));
+ Process->Vm.Flags.AcquiredUnsafe = 1;
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
Thread->OwnsProcessWorkingSetExclusive = TRUE;
}
@@ -1116,19 +1176,43 @@
MiUnlockProcessWorkingSet(IN PEPROCESS Process,
IN PETHREAD Thread)
{
- /* Make sure this process really is owner, and it was a safe acquisition */
+ /* Make sure we are the owner of a safe acquisition */
ASSERT(MI_WS_OWNER(Process));
- /* This can't be checked because Vm is used by MAREAs) */
- //ASSERT(Process->Vm.Flags.AcquiredUnsafe == 0);
+ ASSERT(!MI_IS_WS_UNSAFE(Process));
/* The thread doesn't own it anymore */
ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
Thread->OwnsProcessWorkingSetExclusive = FALSE;
- /* FIXME: Actually release it (we can't because Vm is used by MAREAs) */
-
- /* Unblock APCs */
+ /* Release the lock and re-enable APCs */
+ ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
KeLeaveGuardedRegion();
+}
+
+//
+// Unlocks the working set for the given process
+//
+FORCEINLINE
+VOID
+MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process,
+ IN PETHREAD Thread)
+{
+ /* Make sure we are the owner of an unsafe acquisition */
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
+ ASSERT(MI_WS_OWNER(Process));
+ ASSERT(MI_IS_WS_UNSAFE(Process));
+
+ /* No longer unsafe */
+ Process->Vm.Flags.AcquiredUnsafe = 0;
+
+ /* The thread doesn't own it anymore */
+ ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
+ Thread->OwnsProcessWorkingSetExclusive = FALSE;
+
+ /* Release the lock but don't touch APC state */
+ ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
}
//
@@ -1148,7 +1232,8 @@
/* Thread shouldn't already be owning something */
ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
- /* FIXME: Actually lock it (we can't because Vm is used by MAREAs) */
+ /* Lock this working set */
+ ExAcquirePushLockExclusive(&WorkingSet->WorkingSetMutex);
/* Which working set is this? */
if (WorkingSet == &MmSystemCacheWs)
@@ -1208,10 +1293,66 @@
Thread->OwnsProcessWorkingSetExclusive = FALSE;
}
- /* FIXME: Actually release it (we can't because Vm is used by MAREAs) */
+ /* Release the working set lock */
+ ExReleasePushLockExclusive(&WorkingSet->WorkingSetMutex);
/* Unblock APCs */
KeLeaveGuardedRegion();
+}
+
+FORCEINLINE
+VOID
+MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process,
+ IN PETHREAD Thread,
+ IN BOOLEAN Safe,
+ IN BOOLEAN Shared)
+{
+ ASSERT(MI_WS_OWNER(Process));
+
+ /* Check if the current owner is unsafe */
+ if (MI_IS_WS_UNSAFE(Process))
+ {
+ /* Release unsafely */
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
+ Safe = FALSE;
+ Shared = FALSE;
+ }
+ else if (Thread->OwnsProcessWorkingSetExclusive == 1)
+ {
+ /* Owner is safe and exclusive, release normally */
+ MiUnlockProcessWorkingSet(Process, Thread);
+ Safe = TRUE;
+ Shared = FALSE;
+ }
+ else
+ {
+ /* Owner is shared (implies safe), release normally */
+ ASSERT(FALSE);
+ Safe = TRUE;
+ Shared = TRUE;
+ }
+}
+
+FORCEINLINE
+VOID
+MiLockProcessWorkingSetForFault(IN PEPROCESS Process,
+ IN PETHREAD Thread,
+ IN BOOLEAN Safe,
+ IN BOOLEAN Shared)
+{
+ ASSERT(Shared == FALSE);
+
+ /* Check if this was a safe lock or not */
+ if (Safe)
+ {
+ /* Reacquire safely */
+ MiLockProcessWorkingSet(Process, Thread);
+ }
+ else
+ {
+ /* Reacquire unsafely */
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
+ }
}
//
Modified: trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/procsup.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Mon Sep 3 06:23:31 2012
@@ -135,7 +135,7 @@
Status = STATUS_SUCCESS;
/* Pretend as if we own the working set */
- MiLockProcessWorkingSet(Process, Thread);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Insert the VAD */
ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
@@ -147,7 +147,7 @@
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */
- MiUnlockProcessWorkingSet(Process, Thread);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Release the address space lock */
KeReleaseGuardedMutex(&Process->AddressCreationLock);
@@ -195,7 +195,7 @@
ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
/* Lock the working set */
- MiLockProcessWorkingSet(Process, Thread);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Remove this VAD from the tree */
ASSERT(VadTree->NumberGenericTableElements >= 1);
@@ -205,7 +205,7 @@
MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL);
/* Release the working set */
- MiUnlockProcessWorkingSet(Process, Thread);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Remove the VAD */
ExFreePool(Vad);
@@ -1338,9 +1338,11 @@
/* Lock the process address space from changes */
MmLockAddressSpace(&Process->Vm);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* VM is deleted now */
Process->VmDeleted = TRUE;
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Enumerate the VADs */
VadTree = &Process->VadRoot;
@@ -1350,7 +1352,7 @@
Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
/* Lock the working set */
- MiLockProcessWorkingSet(Process, Thread);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Remove this VAD from the tree */
ASSERT(VadTree->NumberGenericTableElements >= 1);
@@ -1373,7 +1375,7 @@
Vad);
/* Release the working set */
- MiUnlockProcessWorkingSet(Process, Thread);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
}
/* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
@@ -1388,8 +1390,16 @@
ExFreePool(Vad);
}
+ /* Lock the working set */
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
+ ASSERT(Process->CloneRoot == NULL);
+ ASSERT(Process->PhysicalVadRoot == NULL);
+
/* Delete the shared user data section */
MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
+
+ /* Release the working set */
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Release the address space */
MmUnlockAddressSpace(&Process->Vm);
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Mon Sep 3 06:23:31 2012
@@ -84,22 +84,22 @@
ULONG MmCompatibleProtectionMask[8] =
{
PAGE_NOACCESS,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY,
-
+
PAGE_NOACCESS | PAGE_EXECUTE,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE |
PAGE_EXECUTE_READ,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE |
PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
PAGE_EXECUTE_WRITECOPY,
-
+
PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE |
PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
};
@@ -713,11 +713,29 @@
VOID
NTAPI
+MiDereferenceControlArea(IN PCONTROL_AREA ControlArea)
+{
+ KIRQL OldIrql;
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Drop reference counts */
+ ControlArea->NumberOfMappedViews--;
+ ControlArea->NumberOfUserReferences--;
+
+ /* Check if it's time to delete the CA. This releases the lock */
+ MiCheckControlArea(ControlArea, OldIrql);
+}
+
+VOID
+NTAPI
MiRemoveMappedView(IN PEPROCESS CurrentProcess,
IN PMMVAD Vad)
{
KIRQL OldIrql;
PCONTROL_AREA ControlArea;
+ PETHREAD CurrentThread = PsGetCurrentThread();
/* Get the control area */
ControlArea = Vad->ControlArea;
@@ -734,7 +752,7 @@
Vad);
/* Release the working set */
- MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
+ MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
/* Lock the PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
@@ -760,6 +778,8 @@
PVOID DbgBase = NULL;
SIZE_T RegionSize;
NTSTATUS Status;
+ PETHREAD CurrentThread = PsGetCurrentThread();
+ PEPROCESS CurrentProcess = PsGetCurrentProcess();
PAGED_CODE();
/* Check for Mm Region */
@@ -771,7 +791,7 @@
}
/* Check if we should attach to the process */
- if (PsGetCurrentProcess() != Process)
+ if (CurrentProcess != Process)
{
/* The process is different, do an attach */
KeStackAttachProcess(&Process->Pcb, &ApcState);
@@ -837,13 +857,13 @@
/* FIXME: Remove VAD charges */
/* Lock the working set */
- MiLockWorkingSet(PsGetCurrentThread(), &Process->Vm);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
/* Remove the VAD */
ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
- /* Remove the PTEs for this view */
+ /* Remove the PTEs for this view, which also releases the working set lock */
MiRemoveMappedView(Process, Vad);
/* FIXME: Remove commitment */
@@ -1205,7 +1225,8 @@
&Process->VadRoot))
{
DPRINT1("Conflict with SEC_BASED or manually based section!\n");
- return STATUS_CONFLICTING_ADDRESSES; // FIXME: CA Leak
+ MiDereferenceControlArea(ControlArea);
+ return STATUS_CONFLICTING_ADDRESSES;
}
}
@@ -1213,7 +1234,11 @@
/* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */
ASSERT((AllocationType & MEM_RESERVE) == 0); /* ARM3 does not support this */
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
- if (!Vad) return STATUS_INSUFFICIENT_RESOURCES; /* FIXME: CA Leak */
+ if (!Vad)
+ {
+ MiDereferenceControlArea(ControlArea);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
Vad->u4.Banked = (PVOID)0xDEADBABE;
@@ -1244,13 +1269,13 @@
Status = STATUS_SUCCESS;
/* Pretend as if we own the working set */
- MiLockProcessWorkingSet(Process, Thread);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Insert the VAD */
MiInsertVad((PMMVAD)Vad, Process);
/* Release the working set */
- MiUnlockProcessWorkingSet(Process, Thread);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
/* Windows stores this for accounting purposes, do so as well */
if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
@@ -1797,7 +1822,7 @@
PMMPFN Pfn1;
ULONG ProtectionMask, QuotaCharge = 0;
PUSHORT UsedPageTableEntries;
- //PETHREAD Thread = PsGetCurrentThread();
+ PETHREAD Thread = PsGetCurrentThread();
PAGED_CODE();
//
@@ -1829,7 +1854,7 @@
//
// Get the PTE and PDE for the address, as well as the final PTE
//
- //MiLockProcessWorkingSet(Thread, Process);
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
PointerPde = MiAddressToPde(StartingAddress);
PointerPte = MiAddressToPte(StartingAddress);
LastPte = MiAddressToPte(EndingAddress);
@@ -1943,7 +1968,7 @@
//
// Unlock the working set and update quota charges if needed, then return
//
- //MiUnlockProcessWorkingSet(Thread, Process);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
if ((QuotaCharge > 0) && (!DontCharge))
{
FoundVad->u.VadFlags.CommitCharge -= QuotaCharge;
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Mon Sep 3 06:23:31 2012
@@ -205,7 +205,7 @@
IN PEPROCESS CurrentProcess)
{
NTSTATUS Status;
- BOOLEAN WsWasLocked = FALSE, LockChange = FALSE;
+ BOOLEAN WsShared = FALSE, WsSafe = FALSE, LockChange = FALSE;
PETHREAD CurrentThread = PsGetCurrentThread();
/* Must be a non-pool page table, since those are double-mapped already */
@@ -219,13 +219,11 @@
/* Check if the page table is valid */
while (!MmIsAddressValid(PageTableVirtualAddress))
{
- /* Check if the WS is locked */
- if (CurrentThread->OwnsProcessWorkingSetExclusive)
- {
- /* Unlock the working set and remember it was locked */
- MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
- WsWasLocked = TRUE;
- }
+ /* Release the working set lock */
+ MiUnlockProcessWorkingSetForFault(CurrentProcess,
+ CurrentThread,
+ WsSafe,
+ WsShared);
/* Fault it in */
Status = MmAccessFault(FALSE, PageTableVirtualAddress, KernelMode, NULL);
@@ -240,7 +238,10 @@
}
/* Lock the working set again */
- if (WsWasLocked) MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
+ MiLockProcessWorkingSetForFault(CurrentProcess,
+ CurrentThread,
+ WsSafe,
+ WsShared);
/* This flag will be useful later when we do better locking */
LockChange = TRUE;
@@ -1884,8 +1885,9 @@
ULONG ProtectionMask, OldProtect;
BOOLEAN Committed;
NTSTATUS Status = STATUS_SUCCESS;
-
- /* Calcualte base address for the VAD */
+ PETHREAD Thread = PsGetCurrentThread();
+
+ /* Calculate base address for the VAD */
StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
@@ -1896,7 +1898,7 @@
DPRINT1("Invalid protection mask\n");
return STATUS_INVALID_PAGE_PROTECTION;
}
-
+
/* Check for ROS specific memory area */
MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
if ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW))
@@ -2006,7 +2008,8 @@
goto FailPath;
}
- //MiLockProcessWorkingSet(Thread, Process);
+ /* Lock the working set */
+ MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Check if all pages in this range are committed */
Committed = MiIsEntireRangeCommitted(StartingAddress,
@@ -2018,7 +2021,7 @@
/* Fail */
DPRINT1("The entire range is not committed\n");
Status = STATUS_NOT_COMMITTED;
- //MiUnlockProcessWorkingSet(Thread, Process);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
goto FailPath;
}
@@ -2105,7 +2108,7 @@
}
/* Unlock the working set */
- //MiUnlockProcessWorkingSet(Thread, Process);
+ MiUnlockProcessWorkingSetUnsafe(Process, Thread);
}
/* Unlock the address space */
@@ -2278,7 +2281,7 @@
PointerPde = MiAddressToPde(StartingAddress);
PointerPte = MiAddressToPte(StartingAddress);
if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
- MiLockWorkingSet(CurrentThread, &Process->Vm);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
//
// Make the PDE valid, and now loop through each page's worth of data
@@ -2403,7 +2406,7 @@
// release the working set and return the commit reduction accounting.
//
if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
- MiUnlockWorkingSet(CurrentThread, &Process->Vm);
+ MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
return CommitReduction;
}
@@ -3992,10 +3995,10 @@
//
// Lock the working set and insert the VAD into the process VAD tree
//
- MiLockProcessWorkingSet(Process, CurrentThread);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
Vad->ControlArea = NULL; // For Memory-Area hack
MiInsertVad(Vad, Process);
- MiUnlockProcessWorkingSet(Process, CurrentThread);
+ MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
//
// Update the virtual size of the process, and if this is now the highest
@@ -4254,7 +4257,7 @@
//
// Lock the working set while we play with user pages and page tables
//
- //MiLockWorkingSet(CurrentThread, AddressSpace);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
//
// Make the current page table valid, and then loop each page within it
@@ -4335,7 +4338,7 @@
// the target process if it was not the current process. Also dereference the
// target process if this wasn't the case.
//
- //MiUnlockProcessWorkingSet(Process, CurrentThread);
+ MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
Status = STATUS_SUCCESS;
FailPath:
MmUnlockAddressSpace(AddressSpace);
@@ -4584,7 +4587,7 @@
//
// Finally lock the working set and remove the VAD from the VAD tree
//
- MiLockWorkingSet(CurrentThread, AddressSpace);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
}
@@ -4614,7 +4617,7 @@
// the code path above when the caller sets a zero region size
// and the whole VAD is destroyed
//
- MiLockWorkingSet(CurrentThread, AddressSpace);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
}
@@ -4653,7 +4656,7 @@
// and then change the ending address of the VAD to be a bit
// smaller.
//
- MiLockWorkingSet(CurrentThread, AddressSpace);
+ MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
CommitReduction = MiCalculatePageCommitment(StartingAddress,
EndingAddress,
Vad,
@@ -4695,7 +4698,7 @@
// around with process pages.
//
MiDeleteVirtualAddresses(StartingAddress, EndingAddress, NULL);
- MiUnlockWorkingSet(CurrentThread, AddressSpace);
+ MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
Status = STATUS_SUCCESS;
FinalPath: