Miscellaneous fixes for legacy Mm section implementation
- Always allocate a private page for IMAGE_SCN_CNT_UNINITIALIZED_DATA
- Make sure a shared page is present before writing on a COW mapping and making a private copy.
- Fix a race condition : when paging out a file section, old Mm lists all of the process maps, removing them one after the other and lowering the page reference count in the process. Sometimes a page fault occur in the process, the mapping is added, but the page refcount is not bumped because it requires locking the corresponding segment. Manage page refcount under segment lock.
CORE-12047
svn path=/trunk/; revision=72989
HasSwapEntry = MmIsPageSwapEntry(Process, Address);
HasSwapEntry = MmIsPageSwapEntry(Process, Address);
+ /* See if we should use a private page */
+ if ((HasSwapEntry) || (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
{
SWAPENTRY DummyEntry;
/*
* Is it a wait entry?
*/
{
SWAPENTRY DummyEntry;
/*
* Is it a wait entry?
*/
- MmGetPageFileMapping(Process, Address, &SwapEntry);
-
- if (SwapEntry == MM_WAIT_ENTRY)
- MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(AddressSpace);
- MiWaitForPageEvent(NULL, NULL);
- MmLockAddressSpace(AddressSpace);
- return STATUS_MM_RESTART_OPERATION;
- }
+ MmGetPageFileMapping(Process, Address, &SwapEntry);
- /*
- * Must be private page we have swapped out.
- */
+ if (SwapEntry == MM_WAIT_ENTRY)
+ {
+ MmUnlockSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ MiWaitForPageEvent(NULL, NULL);
+ MmLockAddressSpace(AddressSpace);
+ return STATUS_MM_RESTART_OPERATION;
+ }
- /*
- * Sanity check
- */
- if (Segment->Flags & MM_PAGEFILE_SEGMENT)
- {
- DPRINT1("Found a swaped out private page in a pagefile section.\n");
- KeBugCheck(MEMORY_MANAGEMENT);
+ /*
+ * Must be private page we have swapped out.
+ */
+
+ /*
+ * Sanity check
+ */
+ if (Segment->Flags & MM_PAGEFILE_SEGMENT)
+ {
+ DPRINT1("Found a swaped out private page in a pagefile section.\n");
+ KeBugCheck(MEMORY_MANAGEMENT);
+ }
+ MmDeletePageFileMapping(Process, Address, &SwapEntry);
}
MmUnlockSectionSegment(Segment);
}
MmUnlockSectionSegment(Segment);
- MmDeletePageFileMapping(Process, Address, &SwapEntry);
+
+ /* Tell everyone else we are serving the fault. */
MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
MmUnlockAddressSpace(AddressSpace);
MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
MmUnlockAddressSpace(AddressSpace);
KeBugCheck(MEMORY_MANAGEMENT);
}
KeBugCheck(MEMORY_MANAGEMENT);
}
- Status = MmReadFromSwapPage(SwapEntry, Page);
- if (!NT_SUCCESS(Status))
- DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
- KeBugCheck(MEMORY_MANAGEMENT);
+ Status = MmReadFromSwapPage(SwapEntry, Page);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
+ KeBugCheck(MEMORY_MANAGEMENT);
+ }
MmLockAddressSpace(AddressSpace);
MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
Status = MmCreateVirtualMapping(Process,
MmLockAddressSpace(AddressSpace);
MmDeletePageFileMapping(Process, PAddress, &DummyEntry);
Status = MmCreateVirtualMapping(Process,
/*
* Store the swap entry for later use.
*/
/*
* Store the swap entry for later use.
*/
- MmSetSavedSwapEntryPage(Page, SwapEntry);
+ if (HasSwapEntry)
+ MmSetSavedSwapEntryPage(Page, SwapEntry);
/*
* Add the page to the process's working set
/*
* Add the page to the process's working set
- /*
- * Mark the offset within the section as having valid, in-memory
- * data
- */
+ /* Lock both segment and process address space while we proceed. */
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
- Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
- MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
- MmUnlockSectionSegment(Segment);
MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
ASSERT(MmIsPagePresent(Process, PAddress));
MmInsertRmap(Page, Process, Address);
ASSERT(MmIsPagePresent(Process, PAddress));
MmInsertRmap(Page, Process, Address);
+ /* Set this section offset has being backed by our new page. */
+ Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+ MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
+ MmUnlockSectionSegment(Segment);
+
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
SwapEntry = SWAPENTRY_FROM_SSE(Entry);
SwapEntry = SWAPENTRY_FROM_SSE(Entry);
+ /* See if a page op is running on this segment. */
+ if (SwapEntry == MM_WAIT_ENTRY)
+ {
+ MmUnlockSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ MiWaitForPageEvent(NULL, NULL);
+ MmLockAddressSpace(AddressSpace);
+ return STATUS_MM_RESTART_OPERATION;
+ }
+
/*
* Release all our locks and read in the page from disk
*/
/*
* Release all our locks and read in the page from disk
*/
KeBugCheck(MEMORY_MANAGEMENT);
}
KeBugCheck(MEMORY_MANAGEMENT);
}
- /*
- * Mark the offset within the section as having valid, in-memory
- * data
- */
- Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
- MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
- MmUnlockSectionSegment(Segment);
-
/*
* Save the swap entry.
*/
MmSetSavedSwapEntryPage(Page, SwapEntry);
/*
* Save the swap entry.
*/
MmSetSavedSwapEntryPage(Page, SwapEntry);
+
+ /* Map the page into the process address space */
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
+
+ /*
+ * Mark the offset within the section as having valid, in-memory
+ * data
+ */
+ Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
+ MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
+ MmUnlockSectionSegment(Segment);
+
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
else
{
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
}
else
{
- /*
- * If the section offset is already in-memory and valid then just
- * take another reference to the page
- */
-
+ /* We already have a page on this section offset. Map it into the process address space. */
Page = PFN_FROM_SSE(Entry);
Page = PFN_FROM_SSE(Entry);
- MmSharePageEntrySectionSegment(Segment, &Offset);
- MmUnlockSectionSegment(Segment);
-
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
+
+ /* Take a reference on it */
+ MmSharePageEntrySectionSegment(Segment, &Offset);
+ MmUnlockSectionSegment(Segment);
+
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
return(STATUS_SUCCESS);
PMM_REGION Region;
ULONG_PTR Entry;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
PMM_REGION Region;
ULONG_PTR Entry;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
+ /* Make sure we have a page mapping for this address. */
+ Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* This is invalid access ! */
+ return Status;
+ }
+
/*
* Check if the page has already been set readwrite
*/
/*
* Check if the page has already been set readwrite
*/
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
&MemoryArea->Data.SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
- /*
- * Lock the segment
- */
- MmLockSectionSegment(Segment);
-
- OldPage = MmGetPfnForProcess(Process, Address);
- Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
-
- MmUnlockSectionSegment(Segment);
/*
* Check if we are doing COW
/*
* Check if we are doing COW
return(STATUS_ACCESS_VIOLATION);
}
return(STATUS_ACCESS_VIOLATION);
}
- if (IS_SWAP_FROM_SSE(Entry) ||
- PFN_FROM_SSE(Entry) != OldPage)
- {
- /* This is a private page. We must only change the page protection. */
- MmSetPageProtect(Process, Address, Region->Protect);
- return(STATUS_SUCCESS);
- }
-
- if(OldPage == 0)
- DPRINT("OldPage == 0!\n");
-
- /*
- * Get or create a pageop
- */
+ /* Get the page mapping this section offset. */
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
- /*
- * Wait for any other operations to complete
- */
- if (Entry == SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY))
+ /* Get the current page mapping for the process */
+ ASSERT(MmIsPagePresent(Process, PAddress));
+ OldPage = MmGetPfnForProcess(Process, PAddress);
+ ASSERT(OldPage != 0);
+
+ if (IS_SWAP_FROM_SSE(Entry) ||
+ PFN_FROM_SSE(Entry) != OldPage)
{
MmUnlockSectionSegment(Segment);
{
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(AddressSpace);
- MiWaitForPageEvent(NULL, NULL);
- /*
- * Restart the operation
- */
- MmLockAddressSpace(AddressSpace);
- DPRINT("Address 0x%p\n", Address);
- return(STATUS_MM_RESTART_OPERATION);
+ /* This is a private page. We must only change the page protection. */
+ MmSetPageProtect(Process, PAddress, Region->Protect);
+ return(STATUS_SUCCESS);
- MmDeleteRmap(OldPage, Process, PAddress);
- MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
- MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
-
- /*
- * Release locks now we have the pageop
- */
- MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(AddressSpace);
-
*/
MiCopyFromUserPage(NewPage, OldPage);
*/
MiCopyFromUserPage(NewPage, OldPage);
- MmLockAddressSpace(AddressSpace);
+ /*
+ * Unshare the old page.
+ */
+ DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
+ MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
+ MmDeleteRmap(OldPage, Process, PAddress);
+ MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
+ MmUnlockSectionSegment(Segment);
/*
* Set the PTE to point to the new page
*/
/*
* Set the PTE to point to the new page
*/
- MmDeletePageFileMapping(Process, PAddress, &SwapEntry);
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
KeBugCheck(MEMORY_MANAGEMENT);
return(Status);
}
KeBugCheck(MEMORY_MANAGEMENT);
return(Status);
}
-
- /*
- * Unshare the old page.
- */
- DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
MmInsertRmap(NewPage, Process, PAddress);
MmInsertRmap(NewPage, Process, PAddress);
- MmLockSectionSegment(Segment);
- MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
- MmUnlockSectionSegment(Segment);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
MiSetPageEvent(Process, Address);
DPRINT("Address 0x%p\n", Address);
else
{
ULONG_PTR OldEntry;
else
{
ULONG_PTR OldEntry;
+
+ MmLockSectionSegment(Context.Segment);
+
/*
* For non-private pages if the page wasn't direct mapped then
* set it back into the section segment entry so we don't loose
/*
* For non-private pages if the page wasn't direct mapped then
* set it back into the section segment entry so we don't loose
Address);
// If we got here, the previous entry should have been a wait
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
Address);
// If we got here, the previous entry should have been a wait
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
- MmLockSectionSegment(Context.Segment);
OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
+ MmLockSectionSegment(Context.Segment);
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
Status = MmCreateVirtualMapping(Process,
Address,
MemoryArea->Protect,
Address);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
Address);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
+ MmUnlockSectionSegment(Context.Segment);
}
MmUnlockAddressSpace(AddressSpace);
MiSetPageEvent(NULL, NULL);
}
MmUnlockAddressSpace(AddressSpace);
MiSetPageEvent(NULL, NULL);