mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
[NTOS:MM] Implement MmFlushImageSection(MmFlushForDelete)
CORE-17544
This commit is contained in:
parent
b3e9c89725
commit
59cddd15e2
3 changed files with 141 additions and 23 deletions
|
@ -51,6 +51,11 @@ struct _EPROCESS;
|
||||||
struct _MM_RMAP_ENTRY;
|
struct _MM_RMAP_ENTRY;
|
||||||
typedef ULONG_PTR SWAPENTRY;
|
typedef ULONG_PTR SWAPENTRY;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Special IRQL value (found in assertions)
|
||||||
|
//
|
||||||
|
#define MM_NOIRQL ((KIRQL)0xFFFFFFFF)
|
||||||
|
|
||||||
//
|
//
|
||||||
// MmDbgCopyMemory Flags
|
// MmDbgCopyMemory Flags
|
||||||
//
|
//
|
||||||
|
@ -175,6 +180,7 @@ typedef ULONG_PTR SWAPENTRY;
|
||||||
|
|
||||||
typedef struct _MM_SECTION_SEGMENT
|
typedef struct _MM_SECTION_SEGMENT
|
||||||
{
|
{
|
||||||
|
LONG64 RefCount;
|
||||||
PFILE_OBJECT FileObject;
|
PFILE_OBJECT FileObject;
|
||||||
|
|
||||||
FAST_MUTEX Lock; /* lock which protects the page directory */
|
FAST_MUTEX Lock; /* lock which protects the page directory */
|
||||||
|
@ -194,7 +200,6 @@ typedef struct _MM_SECTION_SEGMENT
|
||||||
ULONG Characteristics;
|
ULONG Characteristics;
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
LONG64 RefCount;
|
|
||||||
ULONG SegFlags;
|
ULONG SegFlags;
|
||||||
|
|
||||||
ULONGLONG LastPage;
|
ULONGLONG LastPage;
|
||||||
|
@ -204,9 +209,10 @@ typedef struct _MM_SECTION_SEGMENT
|
||||||
|
|
||||||
typedef struct _MM_IMAGE_SECTION_OBJECT
|
typedef struct _MM_IMAGE_SECTION_OBJECT
|
||||||
{
|
{
|
||||||
PFILE_OBJECT FileObject;
|
|
||||||
|
|
||||||
LONG64 RefCount;
|
LONG64 RefCount;
|
||||||
|
PFILE_OBJECT FileObject;
|
||||||
|
ULONG SectionCount;
|
||||||
|
LONG MapCount;
|
||||||
ULONG SegFlags;
|
ULONG SegFlags;
|
||||||
|
|
||||||
SECTION_IMAGE_INFORMATION ImageInformation;
|
SECTION_IMAGE_INFORMATION ImageInformation;
|
||||||
|
@ -219,6 +225,7 @@ typedef struct _MM_IMAGE_SECTION_OBJECT
|
||||||
#define MM_DATAFILE_SEGMENT (0x2)
|
#define MM_DATAFILE_SEGMENT (0x2)
|
||||||
#define MM_SEGMENT_INDELETE (0x4)
|
#define MM_SEGMENT_INDELETE (0x4)
|
||||||
#define MM_SEGMENT_INCREATE (0x8)
|
#define MM_SEGMENT_INCREATE (0x8)
|
||||||
|
#define MM_IMAGE_SECTION_FLUSH_DELETE (0x10)
|
||||||
|
|
||||||
|
|
||||||
#define MA_GetStartingAddress(_MemoryArea) ((_MemoryArea)->VadNode.StartingVpn << PAGE_SHIFT)
|
#define MA_GetStartingAddress(_MemoryArea) ((_MemoryArea)->VadNode.StartingVpn << PAGE_SHIFT)
|
||||||
|
@ -1471,7 +1478,14 @@ MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea,
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MmDereferenceSegment(PMM_SECTION_SEGMENT Segment);
|
MmDereferenceSegmentWithLock(PMM_SECTION_SEGMENT Segment, KIRQL OldIrql);
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
VOID
|
||||||
|
MmDereferenceSegment(PMM_SECTION_SEGMENT Segment)
|
||||||
|
{
|
||||||
|
MmDereferenceSegmentWithLock(Segment, MM_NOIRQL);
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -230,11 +230,6 @@ extern const ULONG MmProtectToValue[32];
|
||||||
#error Define these please!
|
#error Define these please!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
|
||||||
// Special IRQL value (found in assertions)
|
|
||||||
//
|
|
||||||
#define MM_NOIRQL (KIRQL)0xFFFFFFFF
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Returns the color of a page
|
// Returns the color of a page
|
||||||
//
|
//
|
||||||
|
|
|
@ -989,22 +989,28 @@ FreeSegmentPage(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MmDereferenceSegment(PMM_SECTION_SEGMENT Segment)
|
MmDereferenceSegmentWithLock(PMM_SECTION_SEGMENT Segment, KIRQL OldIrql)
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
BOOLEAN HaveLock = FALSE;
|
||||||
|
|
||||||
/* Lock the PFN lock because we mess around with SectionObjectPointers */
|
/* Lock the PFN lock because we mess around with SectionObjectPointers */
|
||||||
|
if (OldIrql == MM_NOIRQL)
|
||||||
|
{
|
||||||
|
HaveLock = TRUE;
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
|
}
|
||||||
|
|
||||||
if (InterlockedDecrement64(Segment->ReferenceCount) > 0)
|
if (InterlockedDecrement64(Segment->ReferenceCount) > 0)
|
||||||
{
|
{
|
||||||
/* Nothing to do yet */
|
/* Nothing to do yet */
|
||||||
|
if (HaveLock)
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*Segment->Flags |= MM_SEGMENT_INDELETE;
|
*Segment->Flags |= MM_SEGMENT_INDELETE;
|
||||||
|
|
||||||
|
if (HaveLock)
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
|
|
||||||
/* Flush the segment */
|
/* Flush the segment */
|
||||||
|
@ -1013,10 +1019,12 @@ MmDereferenceSegment(PMM_SECTION_SEGMENT Segment)
|
||||||
/* Free the page table. This will flush any remaining dirty data */
|
/* Free the page table. This will flush any remaining dirty data */
|
||||||
MmFreePageTablesSectionSegment(Segment, FreeSegmentPage);
|
MmFreePageTablesSectionSegment(Segment, FreeSegmentPage);
|
||||||
|
|
||||||
|
if (HaveLock)
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
/* Delete the pointer on the file */
|
/* Delete the pointer on the file */
|
||||||
ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment);
|
ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment);
|
||||||
Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
|
Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
|
||||||
|
if (HaveLock)
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
ObDereferenceObject(Segment->FileObject);
|
ObDereferenceObject(Segment->FileObject);
|
||||||
|
|
||||||
|
@ -1030,10 +1038,12 @@ MmDereferenceSegment(PMM_SECTION_SEGMENT Segment)
|
||||||
ULONG NrSegments;
|
ULONG NrSegments;
|
||||||
ULONG i;
|
ULONG i;
|
||||||
|
|
||||||
|
if (HaveLock)
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
/* Delete the pointer on the file */
|
/* Delete the pointer on the file */
|
||||||
ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject);
|
ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject);
|
||||||
ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL;
|
ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL;
|
||||||
|
if (HaveLock)
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
|
|
||||||
ObDereferenceObject(ImageSectionObject->FileObject);
|
ObDereferenceObject(ImageSectionObject->FileObject);
|
||||||
|
@ -2113,9 +2123,13 @@ MmpDeleteSection(PVOID ObjectBody)
|
||||||
if (Section->Segment == NULL)
|
if (Section->Segment == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
KIRQL OldIrql = MiAcquirePfnLock();
|
||||||
|
ImageSectionObject->SectionCount--;
|
||||||
|
|
||||||
/* We just dereference the first segment */
|
/* We just dereference the first segment */
|
||||||
ASSERT(ImageSectionObject->RefCount > 0);
|
ASSERT(ImageSectionObject->RefCount > 0);
|
||||||
MmDereferenceSegment(ImageSectionObject->Segments);
|
MmDereferenceSegmentWithLock(ImageSectionObject->Segments, OldIrql);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2128,8 +2142,11 @@ MmpDeleteSection(PVOID ObjectBody)
|
||||||
if (Segment == NULL)
|
if (Segment == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
KIRQL OldIrql = MiAcquirePfnLock();
|
||||||
Segment->SectionCount--;
|
Segment->SectionCount--;
|
||||||
MmDereferenceSegment(Segment);
|
|
||||||
|
MmDereferenceSegmentWithLock(Segment, OldIrql);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2473,7 +2490,7 @@ grab_segment:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Section->Segment = (PSEGMENT)Segment;
|
Section->Segment = (PSEGMENT)Segment;
|
||||||
Segment->RefCount++;
|
InterlockedIncrement64(&Segment->RefCount);
|
||||||
InterlockedIncrementUL(&Segment->SectionCount);
|
InterlockedIncrementUL(&Segment->SectionCount);
|
||||||
|
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
|
@ -3205,6 +3222,7 @@ grab_image_section_object:
|
||||||
|
|
||||||
ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE;
|
ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE;
|
||||||
ImageSectionObject->RefCount = 1;
|
ImageSectionObject->RefCount = 1;
|
||||||
|
ImageSectionObject->SectionCount = 1;
|
||||||
|
|
||||||
OldIrql = MiAcquirePfnLock();
|
OldIrql = MiAcquirePfnLock();
|
||||||
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
|
if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
|
||||||
|
@ -3281,8 +3299,12 @@ grab_image_section_object:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* If FS driver called for delete, tell them it's not possible anymore. */
|
||||||
|
ImageSectionObject->SegFlags &= ~MM_IMAGE_SECTION_FLUSH_DELETE;
|
||||||
|
|
||||||
/* Take one ref */
|
/* Take one ref */
|
||||||
ImageSectionObject->RefCount++;
|
InterlockedIncrement64(&ImageSectionObject->RefCount);
|
||||||
|
ImageSectionObject->SectionCount++;
|
||||||
|
|
||||||
MiReleasePfnLock(OldIrql);
|
MiReleasePfnLock(OldIrql);
|
||||||
|
|
||||||
|
@ -3603,6 +3625,7 @@ MiRosUnmapViewOfSection(IN PEPROCESS Process,
|
||||||
ASSERT(NT_SUCCESS(Status));
|
ASSERT(NT_SUCCESS(Status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InterlockedDecrement(&ImageSectionObject->MapCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4026,6 +4049,9 @@ MmMapViewOfSection(IN PVOID SectionObject,
|
||||||
|
|
||||||
*BaseAddress = (PVOID)ImageBase;
|
*BaseAddress = (PVOID)ImageBase;
|
||||||
*ViewSize = ImageSize;
|
*ViewSize = ImageSize;
|
||||||
|
|
||||||
|
/* One more map */
|
||||||
|
InterlockedIncrement(&ImageSectionObject->MapCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4172,6 +4198,87 @@ MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
||||||
switch(FlushType)
|
switch(FlushType)
|
||||||
{
|
{
|
||||||
case MmFlushForDelete:
|
case MmFlushForDelete:
|
||||||
|
{
|
||||||
|
KIRQL OldIrql = MiAcquirePfnLock();
|
||||||
|
PMM_IMAGE_SECTION_OBJECT ImageSectionObject = SectionObjectPointer->ImageSectionObject;
|
||||||
|
|
||||||
|
if (!ImageSectionObject || (ImageSectionObject->SegFlags & MM_SEGMENT_INDELETE))
|
||||||
|
{
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we have open sections or mappings on it ? */
|
||||||
|
if ((ImageSectionObject->SectionCount) || (ImageSectionObject->MapCount))
|
||||||
|
{
|
||||||
|
/* We do. No way to delete it */
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There are no sections open on it, but we must still have pages around. Discard everything */
|
||||||
|
ImageSectionObject->SegFlags |= MM_IMAGE_SECTION_FLUSH_DELETE;
|
||||||
|
InterlockedIncrement64(&ImageSectionObject->RefCount);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
|
||||||
|
for (ULONG i = 0; i < ImageSectionObject->NrSegments; i++)
|
||||||
|
{
|
||||||
|
PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
|
||||||
|
LONGLONG Length;
|
||||||
|
|
||||||
|
MmLockSectionSegment(Segment);
|
||||||
|
/* Loop over all entries */
|
||||||
|
LARGE_INTEGER Offset;
|
||||||
|
Offset.QuadPart = 0;
|
||||||
|
|
||||||
|
Length = Segment->Length.QuadPart;
|
||||||
|
if (Length < Segment->RawLength.QuadPart)
|
||||||
|
Length = Segment->RawLength.QuadPart;
|
||||||
|
|
||||||
|
while (Offset.QuadPart < Length)
|
||||||
|
{
|
||||||
|
ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
|
||||||
|
|
||||||
|
/* Shared data must already be discarded, and nobody should be reading it. */
|
||||||
|
ASSERT(!IS_SWAP_FROM_SSE(Entry));
|
||||||
|
if (Entry != 0)
|
||||||
|
{
|
||||||
|
DPRINT1("Freeing page %lx for image section %p\n", PFN_FROM_SSE(Entry), ImageSectionObject);
|
||||||
|
/* Release the page */
|
||||||
|
ASSERT(SHARE_COUNT_FROM_SSE(Entry) == 0);
|
||||||
|
ASSERT(!IS_WRITE_SSE(Entry));
|
||||||
|
ASSERT(MmGetSavedSwapEntryPage(PFN_FROM_SSE(Entry)) == 0);
|
||||||
|
MmSetPageEntrySectionSegment(Segment, &Offset, 0);
|
||||||
|
MmReleasePageMemoryConsumer(MC_USER, PFN_FROM_SSE(Entry));
|
||||||
|
}
|
||||||
|
Offset.QuadPart += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
MmUnlockSectionSegment(Segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab lock again */
|
||||||
|
OldIrql = MiAcquirePfnLock();
|
||||||
|
|
||||||
|
if (!(ImageSectionObject->SegFlags & MM_IMAGE_SECTION_FLUSH_DELETE))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Someone actually created a section while we were not looking.
|
||||||
|
* Drop our ref and deny.
|
||||||
|
*/
|
||||||
|
MmDereferenceSegmentWithLock(&ImageSectionObject->Segments[0], OldIrql);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should be the last one holding a ref here. */
|
||||||
|
ASSERT(ImageSectionObject->RefCount == 1);
|
||||||
|
ASSERT(ImageSectionObject->SectionCount == 0);
|
||||||
|
|
||||||
|
/* Dereference the first segment, this will free everything & release the lock */
|
||||||
|
MmDereferenceSegmentWithLock(&ImageSectionObject->Segments[0], OldIrql);
|
||||||
|
MiReleasePfnLock(OldIrql);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
case MmFlushForWrite:
|
case MmFlushForWrite:
|
||||||
{
|
{
|
||||||
BOOLEAN Ret = TRUE;
|
BOOLEAN Ret = TRUE;
|
||||||
|
@ -4237,6 +4344,9 @@ MmMapViewInSystemSpaceEx (
|
||||||
|
|
||||||
DPRINT("MmMapViewInSystemSpaceEx() called\n");
|
DPRINT("MmMapViewInSystemSpaceEx() called\n");
|
||||||
|
|
||||||
|
/* unsupported for now */
|
||||||
|
ASSERT(Section->u.Flags.Image == 0);
|
||||||
|
|
||||||
Section = SectionObject;
|
Section = SectionObject;
|
||||||
Segment = (PMM_SECTION_SEGMENT)Section->Segment;
|
Segment = (PMM_SECTION_SEGMENT)Section->Segment;
|
||||||
|
|
||||||
|
@ -4761,7 +4871,6 @@ MmFlushSegment(
|
||||||
}
|
}
|
||||||
|
|
||||||
MmUnlockSectionSegment(Segment);
|
MmUnlockSectionSegment(Segment);
|
||||||
|
|
||||||
MmDereferenceSegment(Segment);
|
MmDereferenceSegment(Segment);
|
||||||
|
|
||||||
if (Iosb)
|
if (Iosb)
|
||||||
|
|
Loading…
Reference in a new issue