- Implemented shared segments for images.

- Fixed a memory leakage in page file sections.
- Fixed the locking bug on cow operations.
- Do not increment the page reference count if the share count is incremented.

svn path=/trunk/; revision=7370
This commit is contained in:
Hartmut Birr 2003-12-31 14:52:06 +00:00
parent f8eea2e937
commit e612170f41

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: section.c,v 1.139 2003/12/31 05:33:04 jfilby Exp $ /* $Id: section.c,v 1.140 2003/12/31 14:52:06 hbirr Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/section.c * FILE: ntoskrnl/mm/section.c
@ -292,9 +292,11 @@ BOOLEAN
MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section, MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
PMM_SECTION_SEGMENT Segment, PMM_SECTION_SEGMENT Segment,
ULONG Offset, ULONG Offset,
BOOLEAN Dirty) BOOLEAN Dirty,
BOOLEAN PageOut)
{ {
ULONG Entry; ULONG Entry;
BOOLEAN IsDirectMapped = FALSE;
Entry = MmGetPageEntrySectionSegment(Segment, Offset); Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry == 0) if (Entry == 0)
@ -331,15 +333,16 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
Page.QuadPart = (LONGLONG)PAGE_FROM_SSE(Entry); Page.QuadPart = (LONGLONG)PAGE_FROM_SSE(Entry);
FileObject = Section->FileObject; FileObject = Section->FileObject;
if (FileObject != NULL) if (FileObject != NULL &&
!(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && if ((FileOffset % PAGE_SIZE) == 0 &&
(FileOffset % PAGE_SIZE) == 0 &&
(Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection)) (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
{ {
NTSTATUS Status; NTSTATUS Status;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap; Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
IsDirectMapped = TRUE;
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty); Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
@ -352,7 +355,9 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
SavedSwapEntry = MmGetSavedSwapEntryPage(Page); SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry == 0) if (SavedSwapEntry == 0)
{ {
if (Segment->Flags & MM_PAGEFILE_SEGMENT) if (!PageOut &&
((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)))
{ {
/* /*
* FIXME: * FIXME:
@ -362,18 +367,39 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
* page without a rmap entry. * page without a rmap entry.
*/ */
MmSetPageEntrySectionSegment(Segment, Offset, Entry); MmSetPageEntrySectionSegment(Segment, Offset, Entry);
MmReferencePage(Page);
} }
else else
{ {
MmSetPageEntrySectionSegment(Segment, Offset, 0); MmSetPageEntrySectionSegment(Segment, Offset, 0);
if (!IsDirectMapped)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
} }
} }
else else
{ {
MmSetSavedSwapEntryPage(Page, 0); MmSetSavedSwapEntryPage(Page, 0);
if (Segment->Flags & MM_PAGEFILE_SEGMENT) if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
if (Dirty && !PageOut)
{
/*
* FIXME:
* We hold all locks. Nobody can do something with the current
* process and the current segment (also not within an other process).
*/
NTSTATUS Status;
PMDL Mdl;
Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
MmBuildMdlFromPages(Mdl, (PULONG)&Page);
Status = MmWriteToSwapPage(SavedSwapEntry, Mdl);
if (!NT_SUCCESS(Status))
{
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status);
}
}
MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry)); MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
} }
else else
@ -381,6 +407,7 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
MmSetPageEntrySectionSegment(Segment, Offset, 0); MmSetPageEntrySectionSegment(Segment, Offset, 0);
MmFreeSwapPage(SavedSwapEntry); MmFreeSwapPage(SavedSwapEntry);
} }
MmReleasePageMemoryConsumer(MC_USER, Page);
} }
} }
else else
@ -393,16 +420,18 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea, BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
ULONG SegOffset) ULONG SegOffset)
{ {
PBCB Bcb; if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
PCACHE_SEGMENT CacheSeg; {
PBCB Bcb;
Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap; PCACHE_SEGMENT CacheSeg;
CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset); Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
if (CacheSeg) CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
{ if (CacheSeg)
CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE); {
return TRUE; CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
} return TRUE;
}
}
return FALSE; return FALSE;
} }
@ -445,11 +474,10 @@ MiReadPage(PMEMORY_AREA MemoryArea,
* memory area was mapped at an offset in the file which is page aligned * memory area was mapped at an offset in the file which is page aligned
* then get the related cache segment. * then get the related cache segment.
*/ */
if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && if ((FileOffset % PAGE_SIZE) == 0 &&
(FileOffset % PAGE_SIZE) == 0 && (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
(SegOffset + PAGE_SIZE <= RawLength || !IsImageSection)) !(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
PHYSICAL_ADDRESS Addr;
/* /*
* Get the related cache segment; we use a lower level interface than * Get the related cache segment; we use a lower level interface than
@ -482,10 +510,8 @@ MiReadPage(PMEMORY_AREA MemoryArea,
/* /*
* Retrieve the page from the cache segment that we actually want. * Retrieve the page from the cache segment that we actually want.
*/ */
Addr = MmGetPhysicalAddress((char*)BaseAddress + (*Page) = MmGetPhysicalAddress(BaseAddress +
FileOffset - BaseOffset); FileOffset - BaseOffset);
(*Page) = Addr;
MmReferencePage((*Page));
CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE); CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
} }
@ -708,7 +734,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
} }
Page.QuadPart = (LONGLONG)(PAGE_FROM_SSE(Entry)); Page.QuadPart = (LONGLONG)(PAGE_FROM_SSE(Entry));
MmReferencePage(Page);
MmSharePageEntrySectionSegment(Segment, Offset); MmSharePageEntrySectionSegment(Segment, Offset);
Status = MmCreateVirtualMapping(MemoryArea->Process, Status = MmCreateVirtualMapping(MemoryArea->Process,
@ -1129,7 +1155,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
*/ */
Page.QuadPart = (LONGLONG)PAGE_FROM_SSE(Entry); Page.QuadPart = (LONGLONG)PAGE_FROM_SSE(Entry);
MmReferencePage(Page);
MmSharePageEntrySectionSegment(Segment, Offset); MmSharePageEntrySectionSegment(Segment, Offset);
MmUnlockSectionSegment(Segment); MmUnlockSectionSegment(Segment);
@ -1185,12 +1211,20 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
/* /*
* Check if the page has been paged out or has already been set readwrite * Check if the page has been paged out or has already been set readwrite
*/ */
if (!MmIsPagePresent(AddressSpace->Process, Address) || if (!MmIsPagePresent(AddressSpace->Process, Address))
MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
{ {
DPRINT("Address 0x%.8X\n", Address); DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
if (MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
{
DPRINT("Address 0x%.8X\n", Address);
if (Locked)
{
MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address));
}
return(STATUS_SUCCESS);
}
/* /*
* Find the offset of the page * Find the offset of the page
@ -1329,18 +1363,17 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
} }
if (Locked) if (Locked)
{ {
/* MmUnlockPage(OldPage); */
MmLockPage(NewPage); MmLockPage(NewPage);
} MmUnlockPage(OldPage);
}
/* /*
* Unshare the old page. * Unshare the old page.
*/ */
MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress); MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
MmLockSectionSegment(Segment); MmLockSectionSegment(Segment);
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE); MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE, FALSE);
MmUnlockSectionSegment(Segment); MmUnlockSectionSegment(Segment);
MmReleasePageMemoryConsumer(MC_USER, OldPage);
PageOp->Status = STATUS_SUCCESS; PageOp->Status = STATUS_SUCCESS;
MmspCompleteAndReleasePageOp(PageOp); MmspCompleteAndReleasePageOp(PageOp);
@ -1370,9 +1403,14 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
MmUnsharePageEntrySectionSegment(PageOutContext->Section, MmUnsharePageEntrySectionSegment(PageOutContext->Section,
PageOutContext->Segment, PageOutContext->Segment,
PageOutContext->Offset, PageOutContext->Offset,
PageOutContext->WasDirty); PageOutContext->WasDirty,
TRUE);
} }
MmReleasePageMemoryConsumer(MC_USER, Page); else
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address); DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
} }
@ -1409,7 +1447,8 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
FileObject = Context.Section->FileObject; FileObject = Context.Section->FileObject;
DirectMapped = FALSE; DirectMapped = FALSE;
if (FileObject != NULL) if (FileObject != NULL &&
!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
Bcb = FileObject->SectionObjectPointer->SharedCacheMap; Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
@ -1418,8 +1457,7 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
* memory area was mapped at an offset in the file which is page aligned * memory area was mapped at an offset in the file which is page aligned
* then note this is a direct mapped page. * then note this is a direct mapped page.
*/ */
if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && if ((FileOffset % PAGE_SIZE) == 0 &&
(FileOffset % PAGE_SIZE) == 0 &&
(Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection)) (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
{ {
DirectMapped = TRUE; DirectMapped = TRUE;
@ -1520,7 +1558,7 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
{ {
if(!MiIsPageFromCache(MemoryArea, Context.Offset)) if(!MiIsPageFromCache(MemoryArea, Context.Offset))
{ {
DPRINT1("Direct mapped non private page is not associated with the cache.\n");; DPRINT1("Direct mapped non private page is not associated with the cache.\n");
KEBUGCHECK(0); KEBUGCHECK(0);
} }
} }
@ -1537,9 +1575,9 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
*/ */
if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0) if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
{ {
if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT)) if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT) &&
!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
CHECKPOINT1;
KEBUGCHECK(0); KEBUGCHECK(0);
} }
} }
@ -1552,9 +1590,11 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
* we can't free the page at this point. * we can't free the page at this point.
*/ */
SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
if (!Context.WasDirty && if (!Context.WasDirty &&
!(SwapEntry == 0 && Context.Segment->Flags & MM_PAGEFILE_SEGMENT)) !(SwapEntry == 0 &&
(Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
Context.Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED)))
{ {
if (Context.Private) if (Context.Private)
{ {
@ -1775,7 +1815,8 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
FileObject = Section->FileObject; FileObject = Section->FileObject;
DirectMapped = FALSE; DirectMapped = FALSE;
if (FileObject != NULL) if (FileObject != NULL &&
!(Segment->Characteristics & IMAGE_SECTION_CHAR_SHARED))
{ {
Bcb = FileObject->SectionObjectPointer->SharedCacheMap; Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
@ -1784,8 +1825,7 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
* memory area was mapped at an offset in the file which is page aligned * memory area was mapped at an offset in the file which is page aligned
* then note this is a direct mapped page. * then note this is a direct mapped page.
*/ */
if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && if ((Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
(Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
(Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection)) (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
{ {
DirectMapped = TRUE; DirectMapped = TRUE;
@ -2013,6 +2053,43 @@ MmQuerySectionView(PMEMORY_AREA MemoryArea,
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
VOID
MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment)
{
ULONG Length;
ULONG Offset;
ULONG Entry;
ULONG SavedSwapEntry;
PHYSICAL_ADDRESS Page;
Page.u.HighPart = 0;
Length = PAGE_ROUND_UP(Segment->Length);
for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
{
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry)
{
if (IS_SWAP_FROM_SSE(Entry))
{
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
}
else
{
Page.u.LowPart = PAGE_FROM_SSE(Entry);
SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry != 0)
{
MmSetSavedSwapEntryPage(Page, 0);
MmFreeSwapPage(SavedSwapEntry);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
}
MmSetPageEntrySectionSegment(Segment, Offset, 0);
}
}
}
VOID STDCALL VOID STDCALL
MmpDeleteSection(PVOID ObjectBody) MmpDeleteSection(PVOID ObjectBody)
{ {
@ -2023,6 +2100,7 @@ MmpDeleteSection(PVOID ObjectBody)
{ {
ULONG i; ULONG i;
ULONG NrSegments; ULONG NrSegments;
ULONG RefCount;
PMM_SECTION_SEGMENT SectionSegments; PMM_SECTION_SEGMENT SectionSegments;
SectionSegments = Section->ImageSection->Segments; SectionSegments = Section->ImageSection->Segments;
@ -2030,38 +2108,26 @@ MmpDeleteSection(PVOID ObjectBody)
for (i = 0; i < NrSegments; i++) for (i = 0; i < NrSegments; i++)
{ {
InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount); if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
{
MmLockSectionSegment(&SectionSegments[i]);
}
RefCount = InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
if (SectionSegments[i].Characteristics & IMAGE_SECTION_CHAR_SHARED)
{
if (RefCount == 0)
{
MmpFreePageFileSegment(&SectionSegments[i]);
}
MmUnlockSectionSegment(&SectionSegments[i]);
}
} }
} }
else else
{ {
if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT) if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
{ {
ULONG Offset; MmpFreePageFileSegment(Section->Segment);
ULONG Length;
ULONG Entry;
PMM_SECTION_SEGMENT Segment;
Segment = Section->Segment;
Length = PAGE_ROUND_UP(Segment->Length);
for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
{
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry)
{
if (IS_SWAP_FROM_SSE(Entry))
{
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
}
else
{
PHYSICAL_ADDRESS Page;
Page.QuadPart = (LONGLONG)PAGE_FROM_SSE(Entry);
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
}
MmFreePageTablesSectionSegment(Section->Segment); MmFreePageTablesSectionSegment(Section->Segment);
ExFreePool(Section->Segment); ExFreePool(Section->Segment);
Section->Segment = NULL; Section->Segment = NULL;
@ -2834,7 +2900,7 @@ MmCreateImageSection(PHANDLE SectionHandle,
SectionSegments[0].Flags = 0; SectionSegments[0].Flags = 0;
SectionSegments[0].ReferenceCount = 1; SectionSegments[0].ReferenceCount = 1;
SectionSegments[0].VirtualAddress = 0; SectionSegments[0].VirtualAddress = 0;
SectionSegments[0].WriteCopy = FALSE; SectionSegments[0].WriteCopy = TRUE;
ExInitializeFastMutex(&SectionSegments[0].Lock); ExInitializeFastMutex(&SectionSegments[0].Lock);
for (i = 1; i < NrSegments; i++) for (i = 1; i < NrSegments; i++)
{ {
@ -3349,8 +3415,7 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
else else
{ {
MmDeleteRmap(PhysAddr, MArea->Process, Address); MmDeleteRmap(PhysAddr, MArea->Process, Address);
MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty); MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty, FALSE);
MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
} }
} }
} }