https://git.reactos.org/?p=reactos.git;a=commitdiff;h=59cddd15e277dd55b22287...
commit 59cddd15e277dd55b222876ca8f571a0add56321 Author: Jérôme Gardou jerome.gardou@reactos.org AuthorDate: Mon Jun 7 19:31:24 2021 +0200 Commit: Jérôme Gardou zefklop@users.noreply.github.com CommitDate: Fri Jun 25 10:28:51 2021 +0200
[NTOS:MM] Implement MmFlushImageSection(MmFlushForDelete)
CORE-17544 --- ntoskrnl/include/internal/mm.h | 22 +++++-- ntoskrnl/mm/ARM3/miarm.h | 5 -- ntoskrnl/mm/section.c | 137 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 141 insertions(+), 23 deletions(-)
diff --git a/ntoskrnl/include/internal/mm.h b/ntoskrnl/include/internal/mm.h index 0b75e613687..e8ace692bd2 100644 --- a/ntoskrnl/include/internal/mm.h +++ b/ntoskrnl/include/internal/mm.h @@ -51,6 +51,11 @@ struct _EPROCESS; struct _MM_RMAP_ENTRY; typedef ULONG_PTR SWAPENTRY;
+// +// Special IRQL value (found in assertions) +// +#define MM_NOIRQL ((KIRQL)0xFFFFFFFF) + // // MmDbgCopyMemory Flags // @@ -175,6 +180,7 @@ typedef ULONG_PTR SWAPENTRY;
typedef struct _MM_SECTION_SEGMENT { + LONG64 RefCount; PFILE_OBJECT FileObject;
FAST_MUTEX Lock; /* lock which protects the page directory */ @@ -194,7 +200,6 @@ typedef struct _MM_SECTION_SEGMENT ULONG Characteristics; } Image;
- LONG64 RefCount; ULONG SegFlags;
ULONGLONG LastPage; @@ -204,9 +209,10 @@ typedef struct _MM_SECTION_SEGMENT
typedef struct _MM_IMAGE_SECTION_OBJECT { - PFILE_OBJECT FileObject; - LONG64 RefCount; + PFILE_OBJECT FileObject; + ULONG SectionCount; + LONG MapCount; ULONG SegFlags;
SECTION_IMAGE_INFORMATION ImageInformation; @@ -219,6 +225,7 @@ typedef struct _MM_IMAGE_SECTION_OBJECT #define MM_DATAFILE_SEGMENT (0x2) #define MM_SEGMENT_INDELETE (0x4) #define MM_SEGMENT_INCREATE (0x8) +#define MM_IMAGE_SECTION_FLUSH_DELETE (0x10)
#define MA_GetStartingAddress(_MemoryArea) ((_MemoryArea)->VadNode.StartingVpn << PAGE_SHIFT) @@ -1471,7 +1478,14 @@ MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea,
VOID 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 NTAPI diff --git a/ntoskrnl/mm/ARM3/miarm.h b/ntoskrnl/mm/ARM3/miarm.h index 721c66c54bb..6d2f2753bb5 100644 --- a/ntoskrnl/mm/ARM3/miarm.h +++ b/ntoskrnl/mm/ARM3/miarm.h @@ -230,11 +230,6 @@ extern const ULONG MmProtectToValue[32]; #error Define these please! #endif
-// -// Special IRQL value (found in assertions) -// -#define MM_NOIRQL (KIRQL)0xFFFFFFFF - // // Returns the color of a page // diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index d758e8d3de0..25d8db8561c 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -989,23 +989,29 @@ FreeSegmentPage(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
VOID 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 */ - OldIrql = MiAcquirePfnLock(); + if (OldIrql == MM_NOIRQL) + { + HaveLock = TRUE; + OldIrql = MiAcquirePfnLock(); + }
if (InterlockedDecrement64(Segment->ReferenceCount) > 0) { /* Nothing to do yet */ - MiReleasePfnLock(OldIrql); + if (HaveLock) + MiReleasePfnLock(OldIrql); return; }
*Segment->Flags |= MM_SEGMENT_INDELETE;
- MiReleasePfnLock(OldIrql); + if (HaveLock) + MiReleasePfnLock(OldIrql);
/* Flush the segment */ if (*Segment->Flags & MM_DATAFILE_SEGMENT) @@ -1013,11 +1019,13 @@ MmDereferenceSegment(PMM_SECTION_SEGMENT Segment) /* Free the page table. This will flush any remaining dirty data */ MmFreePageTablesSectionSegment(Segment, FreeSegmentPage);
- OldIrql = MiAcquirePfnLock(); + if (HaveLock) + OldIrql = MiAcquirePfnLock(); /* Delete the pointer on the file */ ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment); Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL; - MiReleasePfnLock(OldIrql); + if (HaveLock) + MiReleasePfnLock(OldIrql); ObDereferenceObject(Segment->FileObject);
ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); @@ -1030,11 +1038,13 @@ MmDereferenceSegment(PMM_SECTION_SEGMENT Segment) ULONG NrSegments; ULONG i;
- OldIrql = MiAcquirePfnLock(); + if (HaveLock) + OldIrql = MiAcquirePfnLock(); /* Delete the pointer on the file */ ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject); ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL; - MiReleasePfnLock(OldIrql); + if (HaveLock) + MiReleasePfnLock(OldIrql);
ObDereferenceObject(ImageSectionObject->FileObject);
@@ -2113,9 +2123,13 @@ MmpDeleteSection(PVOID ObjectBody) if (Section->Segment == NULL) return;
+ KIRQL OldIrql = MiAcquirePfnLock(); + ImageSectionObject->SectionCount--; + /* We just dereference the first segment */ ASSERT(ImageSectionObject->RefCount > 0); - MmDereferenceSegment(ImageSectionObject->Segments); + MmDereferenceSegmentWithLock(ImageSectionObject->Segments, OldIrql); + MiReleasePfnLock(OldIrql); } else { @@ -2128,8 +2142,11 @@ MmpDeleteSection(PVOID ObjectBody) if (Segment == NULL) return;
+ KIRQL OldIrql = MiAcquirePfnLock(); Segment->SectionCount--; - MmDereferenceSegment(Segment); + + MmDereferenceSegmentWithLock(Segment, OldIrql); + MiReleasePfnLock(OldIrql); } }
@@ -2473,7 +2490,7 @@ grab_segment: else { Section->Segment = (PSEGMENT)Segment; - Segment->RefCount++; + InterlockedIncrement64(&Segment->RefCount); InterlockedIncrementUL(&Segment->SectionCount);
MiReleasePfnLock(OldIrql); @@ -3205,6 +3222,7 @@ grab_image_section_object:
ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE; ImageSectionObject->RefCount = 1; + ImageSectionObject->SectionCount = 1;
OldIrql = MiAcquirePfnLock(); if (FileObject->SectionObjectPointer->ImageSectionObject != NULL) @@ -3281,8 +3299,12 @@ grab_image_section_object: } else { + /* If FS driver called for delete, tell them it's not possible anymore. */ + ImageSectionObject->SegFlags &= ~MM_IMAGE_SECTION_FLUSH_DELETE; + /* Take one ref */ - ImageSectionObject->RefCount++; + InterlockedIncrement64(&ImageSectionObject->RefCount); + ImageSectionObject->SectionCount++;
MiReleasePfnLock(OldIrql);
@@ -3603,6 +3625,7 @@ MiRosUnmapViewOfSection(IN PEPROCESS Process, ASSERT(NT_SUCCESS(Status)); } } + InterlockedDecrement(&ImageSectionObject->MapCount); } else { @@ -4026,6 +4049,9 @@ MmMapViewOfSection(IN PVOID SectionObject,
*BaseAddress = (PVOID)ImageBase; *ViewSize = ImageSize; + + /* One more map */ + InterlockedIncrement(&ImageSectionObject->MapCount); } else { @@ -4172,6 +4198,87 @@ MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, switch(FlushType) { 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: { BOOLEAN Ret = TRUE; @@ -4237,6 +4344,9 @@ MmMapViewInSystemSpaceEx (
DPRINT("MmMapViewInSystemSpaceEx() called\n");
+ /* unsupported for now */ + ASSERT(Section->u.Flags.Image == 0); + Section = SectionObject; Segment = (PMM_SECTION_SEGMENT)Section->Segment;
@@ -4761,7 +4871,6 @@ MmFlushSegment( }
MmUnlockSectionSegment(Segment); - MmDereferenceSegment(Segment);
if (Iosb)