https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d8cdb89fb03006595dc40a...
commit d8cdb89fb03006595dc40ac23db5267b8d9d9c09 Author: Jérôme Gardou jerome.gardou@reactos.org AuthorDate: Fri Nov 6 09:39:31 2020 +0100 Commit: Jérôme Gardou jerome.gardou@reactos.org CommitDate: Wed Feb 3 09:41:22 2021 +0100
[NTOSKRNL] Overhaul Cc and Mm relationship
Previously, when creating a file section, Mm requested Cc to cache the file, then Cc would request pages from Mm, then Mm would request them back to serve its file-mapping role Now, Mm does it all by itself. If file cahcing is requested by the FS driver, then Cc creates a file mapping and uses that to serve its purpose.
This is a rewrite of Cc --- ntoskrnl/cache/section/sptab.c | 3 - ntoskrnl/cc/copy.c | 557 ++++------- ntoskrnl/cc/fs.c | 58 +- ntoskrnl/cc/pin.c | 234 ++--- ntoskrnl/cc/view.c | 495 ++++------ ntoskrnl/ex/init.c | 2 - ntoskrnl/ex/sysinfo.c | 12 +- ntoskrnl/include/internal/cc.h | 30 +- ntoskrnl/include/internal/mm.h | 82 +- ntoskrnl/mm/ARM3/section.c | 32 +- ntoskrnl/mm/ARM3/virtual.c | 8 +- ntoskrnl/mm/ARM3/zeropage.c | 2 +- ntoskrnl/mm/balance.c | 12 - ntoskrnl/mm/pagefile.c | 5 +- ntoskrnl/mm/rmap.c | 315 ++++--- ntoskrnl/mm/section.c | 2032 ++++++++++++++++------------------------ ntoskrnl/po/power.c | 4 +- 17 files changed, 1518 insertions(+), 2365 deletions(-)
diff --git a/ntoskrnl/cache/section/sptab.c b/ntoskrnl/cache/section/sptab.c index 454fb25af42..7a2481a4752 100644 --- a/ntoskrnl/cache/section/sptab.c +++ b/ntoskrnl/cache/section/sptab.c @@ -187,9 +187,6 @@ _MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, ASSERT(Segment->Locked); ASSERT(!IS_SWAP_FROM_SSE(Entry) || !IS_DIRTY_SSE(Entry));
- if (Entry && !IS_SWAP_FROM_SSE(Entry)) - MmGetRmapListHeadPage(PFN_FROM_SSE(Entry)); - PageTable = MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);
if (!PageTable) return STATUS_NO_MEMORY; diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index 1f731716b1f..5bb14cc210a 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -20,13 +20,6 @@ static PFN_NUMBER CcZeroPage = 0;
#define MAX_ZERO_LENGTH (256 * 1024)
-typedef enum _CC_COPY_OPERATION -{ - CcOperationRead, - CcOperationWrite, - CcOperationZero -} CC_COPY_OPERATION; - typedef enum _CC_CAN_WRITE_RETRY { FirstTry = 0, @@ -35,7 +28,7 @@ typedef enum _CC_CAN_WRITE_RETRY RetryMasterLocked = 255, } CC_CAN_WRITE_RETRY;
-ULONG CcRosTraceLevel = 0; +ULONG CcRosTraceLevel = CC_API_DEBUG; ULONG CcFastMdlReadWait; ULONG CcFastMdlReadNotPossible; ULONG CcFastReadNotPossible; @@ -76,338 +69,6 @@ CcInitCacheZeroPage ( MiZeroPhysicalPage(CcZeroPage); }
-NTSTATUS -NTAPI -CcReadVirtualAddress ( - PROS_VACB Vacb) -{ - ULONG Size; - PMDL Mdl; - NTSTATUS Status; - IO_STATUS_BLOCK IoStatus; - KEVENT Event; - ULARGE_INTEGER LargeSize; - - LargeSize.QuadPart = Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart; - if (LargeSize.QuadPart > VACB_MAPPING_GRANULARITY) - { - LargeSize.QuadPart = VACB_MAPPING_GRANULARITY; - } - Size = LargeSize.LowPart; - - Size = ROUND_TO_PAGES(Size); - ASSERT(Size <= VACB_MAPPING_GRANULARITY); - ASSERT(Size > 0); - - Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL); - if (!Mdl) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - Status = STATUS_SUCCESS; - _SEH2_TRY - { - MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess); - } - _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - DPRINT1("MmProbeAndLockPages failed with: %lx for %p (%p, %p)\n", Status, Mdl, Vacb, Vacb->BaseAddress); - KeBugCheck(CACHE_MANAGER); - } _SEH2_END; - - if (NT_SUCCESS(Status)) - { - Mdl->MdlFlags |= MDL_IO_PAGE_READ; - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = IoStatus.Status; - } - - MmUnlockPages(Mdl); - } - - IoFreeMdl(Mdl); - - if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) - { - DPRINT1("IoPageRead failed, Status %x\n", Status); - return Status; - } - - if (Size < VACB_MAPPING_GRANULARITY) - { - RtlZeroMemory((char*)Vacb->BaseAddress + Size, - VACB_MAPPING_GRANULARITY - Size); - } - - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CcWriteVirtualAddress ( - PROS_VACB Vacb) -{ - ULONG Size; - PMDL Mdl; - NTSTATUS Status; - IO_STATUS_BLOCK IoStatus; - KEVENT Event; - ULARGE_INTEGER LargeSize; - - LargeSize.QuadPart = Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart; - if (LargeSize.QuadPart > VACB_MAPPING_GRANULARITY) - { - LargeSize.QuadPart = VACB_MAPPING_GRANULARITY; - } - Size = LargeSize.LowPart; - // - // Nonpaged pool PDEs in ReactOS must actually be synchronized between the - // MmGlobalPageDirectory and the real system PDE directory. What a mess... - // - { - ULONG i = 0; - do - { - MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT))); - } while (++i < (Size >> PAGE_SHIFT)); - } - - ASSERT(Size <= VACB_MAPPING_GRANULARITY); - ASSERT(Size > 0); - - Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL); - if (!Mdl) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - Status = STATUS_SUCCESS; - _SEH2_TRY - { - MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess); - } - _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - DPRINT1("MmProbeAndLockPages failed with: %lx for %p (%p, %p)\n", Status, Mdl, Vacb, Vacb->BaseAddress); - KeBugCheck(CACHE_MANAGER); - } _SEH2_END; - - if (NT_SUCCESS(Status)) - { - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = IoStatus.Status; - } - - MmUnlockPages(Mdl); - } - IoFreeMdl(Mdl); - if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) - { - DPRINT1("IoPageWrite failed, Status %x\n", Status); - return Status; - } - - return STATUS_SUCCESS; -} - -NTSTATUS -ReadWriteOrZero( - _Inout_ PVOID BaseAddress, - _Inout_opt_ PVOID Buffer, - _In_ ULONG Length, - _In_ CC_COPY_OPERATION Operation) -{ - NTSTATUS Status = STATUS_SUCCESS; - - if (Operation == CcOperationZero) - { - /* Zero */ - RtlZeroMemory(BaseAddress, Length); - } - else - { - _SEH2_TRY - { - if (Operation == CcOperationWrite) - RtlCopyMemory(BaseAddress, Buffer, Length); - else - RtlCopyMemory(Buffer, BaseAddress, Length); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - } - return Status; -} - -BOOLEAN -CcCopyData ( - _In_ PFILE_OBJECT FileObject, - _In_ LONGLONG FileOffset, - _Inout_ PVOID Buffer, - _In_ LONGLONG Length, - _In_ CC_COPY_OPERATION Operation, - _In_ BOOLEAN Wait, - _Out_ PIO_STATUS_BLOCK IoStatus) -{ - NTSTATUS Status; - LONGLONG CurrentOffset; - ULONG BytesCopied; - KIRQL OldIrql; - PROS_SHARED_CACHE_MAP SharedCacheMap; - PLIST_ENTRY ListEntry; - PROS_VACB Vacb; - ULONG PartialLength; - PVOID BaseAddress; - BOOLEAN Valid; - PPRIVATE_CACHE_MAP PrivateCacheMap; - - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - PrivateCacheMap = FileObject->PrivateCacheMap; - CurrentOffset = FileOffset; - BytesCopied = 0; - - if (!Wait) - { - /* test if the requested data is available */ - KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); - /* FIXME: this loop doesn't take into account areas that don't have - * a VACB in the list yet */ - ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink; - while (ListEntry != &SharedCacheMap->CacheMapVacbListHead) - { - Vacb = CONTAINING_RECORD(ListEntry, - ROS_VACB, - CacheMapVacbListEntry); - ListEntry = ListEntry->Flink; - if (!Vacb->Valid && - DoRangesIntersect(Vacb->FileOffset.QuadPart, - VACB_MAPPING_GRANULARITY, - CurrentOffset, Length)) - { - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); - /* data not available */ - return FALSE; - } - if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length) - break; - } - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); - } - - PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY; - if (PartialLength != 0) - { - PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength); - Status = CcRosRequestVacb(SharedCacheMap, - ROUND_DOWN(CurrentOffset, - VACB_MAPPING_GRANULARITY), - &BaseAddress, - &Valid, - &Vacb); - if (!NT_SUCCESS(Status)) - ExRaiseStatus(Status); - if (!Valid) - { - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - ExRaiseStatus(Status); - } - } - Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY, - Buffer, - PartialLength, - Operation); - - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE); - - if (!NT_SUCCESS(Status)) - ExRaiseStatus(STATUS_INVALID_USER_BUFFER); - - Length -= PartialLength; - CurrentOffset += PartialLength; - BytesCopied += PartialLength; - - if (Operation != CcOperationZero) - Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength); - } - - while (Length > 0) - { - ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0); - PartialLength = min(VACB_MAPPING_GRANULARITY, Length); - Status = CcRosRequestVacb(SharedCacheMap, - CurrentOffset, - &BaseAddress, - &Valid, - &Vacb); - if (!NT_SUCCESS(Status)) - ExRaiseStatus(Status); - if (!Valid && - (Operation == CcOperationRead || - PartialLength < VACB_MAPPING_GRANULARITY)) - { - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - ExRaiseStatus(Status); - } - } - Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation); - - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE); - - if (!NT_SUCCESS(Status)) - ExRaiseStatus(STATUS_INVALID_USER_BUFFER); - - Length -= PartialLength; - CurrentOffset += PartialLength; - BytesCopied += PartialLength; - - if (Operation != CcOperationZero) - Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength); - } - - /* If that was a successful sync read operation, let's handle read ahead */ - if (Operation == CcOperationRead && Length == 0 && Wait) - { - /* If file isn't random access and next read may get us cross VACB boundary, - * schedule next read - */ - if (!BooleanFlagOn(FileObject->Flags, FO_RANDOM_ACCESS) && - (CurrentOffset - 1) / VACB_MAPPING_GRANULARITY != (CurrentOffset + BytesCopied - 1) / VACB_MAPPING_GRANULARITY) - { - CcScheduleReadAhead(FileObject, (PLARGE_INTEGER)&FileOffset, BytesCopied); - } - - /* And update read history in private cache map */ - PrivateCacheMap->FileOffset1.QuadPart = PrivateCacheMap->FileOffset2.QuadPart; - PrivateCacheMap->BeyondLastByte1.QuadPart = PrivateCacheMap->BeyondLastByte2.QuadPart; - PrivateCacheMap->FileOffset2.QuadPart = FileOffset; - PrivateCacheMap->BeyondLastByte2.QuadPart = FileOffset + BytesCopied; - } - - IoStatus->Status = STATUS_SUCCESS; - IoStatus->Information = BytesCopied; - return TRUE; -} - VOID CcPostDeferredWrites(VOID) { @@ -492,8 +153,6 @@ CcPerformReadAhead( PROS_SHARED_CACHE_MAP SharedCacheMap; PROS_VACB Vacb; ULONG PartialLength; - PVOID BaseAddress; - BOOLEAN Valid; ULONG Length; PPRIVATE_CACHE_MAP PrivateCacheMap; BOOLEAN Locked; @@ -556,10 +215,7 @@ CcPerformReadAhead( { PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength); Status = CcRosRequestVacb(SharedCacheMap, - ROUND_DOWN(CurrentOffset, - VACB_MAPPING_GRANULARITY), - &BaseAddress, - &Valid, + ROUND_DOWN(CurrentOffset, VACB_MAPPING_GRANULARITY), &Vacb); if (!NT_SUCCESS(Status)) { @@ -567,15 +223,13 @@ CcPerformReadAhead( goto Clear; }
- if (!Valid) + Status = CcRosEnsureVacbResident(Vacb, TRUE, FALSE, + CurrentOffset % VACB_MAPPING_GRANULARITY, PartialLength); + if (!NT_SUCCESS(Status)) { - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - DPRINT1("Failed to read data: %lx!\n", Status); - goto Clear; - } + CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); + DPRINT1("Failed to read data: %lx!\n", Status); + goto Clear; }
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); @@ -590,8 +244,6 @@ CcPerformReadAhead( PartialLength = min(VACB_MAPPING_GRANULARITY, Length); Status = CcRosRequestVacb(SharedCacheMap, CurrentOffset, - &BaseAddress, - &Valid, &Vacb); if (!NT_SUCCESS(Status)) { @@ -599,15 +251,12 @@ CcPerformReadAhead( goto Clear; }
- if (!Valid) + Status = CcRosEnsureVacbResident(Vacb, TRUE, FALSE, 0, PartialLength); + if (!NT_SUCCESS(Status)) { - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - DPRINT1("Failed to read data: %lx!\n", Status); - goto Clear; - } + CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); + DPRINT1("Failed to read data: %lx!\n", Status); + goto Clear; }
CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); @@ -811,6 +460,12 @@ CcCopyRead ( OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus) { + PROS_VACB Vacb; + PROS_SHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + NTSTATUS Status; + LONGLONG CurrentOffset; + LONGLONG ReadEnd = FileOffset->QuadPart + Length; + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n", FileObject, FileOffset->QuadPart, Length, Wait);
@@ -819,13 +474,58 @@ CcCopyRead ( FileObject, FileOffset->QuadPart, Length, Wait, Buffer, IoStatus);
- return CcCopyData(FileObject, - FileOffset->QuadPart, - Buffer, - Length, - CcOperationRead, - Wait, - IoStatus); + if (!SharedCacheMap) + return FALSE; + + /* Documented to ASSERT, but KMTests test this case... */ + // ASSERT((FileOffset->QuadPart + Length) <= SharedCacheMap->FileSize.QuadPart); + + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = 0; + + CurrentOffset = FileOffset->QuadPart; + while(CurrentOffset < ReadEnd) + { + Status = CcRosGetVacb(SharedCacheMap, CurrentOffset, &Vacb); + if (!NT_SUCCESS(Status)) + { + ExRaiseStatus(Status); + return FALSE; + } + + _SEH2_TRY + { + ULONG VacbOffset = CurrentOffset % VACB_MAPPING_GRANULARITY; + ULONG VacbLength = min(Length, VACB_MAPPING_GRANULARITY - VacbOffset); + SIZE_T CopyLength = VacbLength; + + if (!CcRosEnsureVacbResident(Vacb, Wait, FALSE, VacbOffset, VacbLength)) + return FALSE; + + /* Do not copy past the section */ + if (CurrentOffset + VacbLength > SharedCacheMap->SectionSize.QuadPart) + CopyLength = SharedCacheMap->SectionSize.QuadPart - CurrentOffset; + if (CopyLength != 0) + RtlCopyMemory(Buffer, (PUCHAR)Vacb->BaseAddress + VacbOffset, CopyLength); + + /* Zero-out the buffer tail if needed */ + if (CopyLength < VacbLength) + RtlZeroMemory((PUCHAR)Buffer + CopyLength, VacbLength - CopyLength); + + IoStatus->Information += VacbLength; + + Buffer = (PVOID)((ULONG_PTR)Buffer + VacbLength); + CurrentOffset += VacbLength; + Length -= VacbLength; + } + _SEH2_FINALLY + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); + } + _SEH2_END; + } + + return TRUE; }
/* @@ -840,7 +540,11 @@ CcCopyWrite ( IN BOOLEAN Wait, IN PVOID Buffer) { - IO_STATUS_BLOCK IoStatus; + PROS_VACB Vacb; + PROS_SHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + NTSTATUS Status; + LONGLONG CurrentOffset; + LONGLONG WriteEnd = FileOffset->QuadPart + Length;
CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n", FileObject, FileOffset->QuadPart, Length, Wait, Buffer); @@ -849,13 +553,48 @@ CcCopyWrite ( "Length %lu, Wait %u, Buffer 0x%p)\n", FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
- return CcCopyData(FileObject, - FileOffset->QuadPart, - Buffer, - Length, - CcOperationWrite, - Wait, - &IoStatus); + if (!SharedCacheMap) + return FALSE; + + /* FIXME: Honor FileObject FO_WRITE_THROUGH flag */ + + ASSERT((FileOffset->QuadPart + Length) <= SharedCacheMap->FileSize.QuadPart); + + CurrentOffset = FileOffset->QuadPart; + while(CurrentOffset < WriteEnd) + { + ULONG VacbOffset = CurrentOffset % VACB_MAPPING_GRANULARITY; + ULONG VacbLength = min(Length, VACB_MAPPING_GRANULARITY - VacbOffset); + + Status = CcRosGetVacb(SharedCacheMap, CurrentOffset, &Vacb); + if (!NT_SUCCESS(Status)) + { + ExRaiseStatus(Status); + return FALSE; + } + + _SEH2_TRY + { + if (!CcRosEnsureVacbResident(Vacb, Wait, FALSE, VacbOffset, VacbLength)) + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); + return FALSE; + } + + RtlCopyMemory((PVOID)((ULONG_PTR)Vacb->BaseAddress + VacbOffset), Buffer, VacbLength); + + Buffer = (PVOID)((ULONG_PTR)Buffer + VacbLength); + CurrentOffset += VacbLength; + Length -= VacbLength; + } + _SEH2_FINALLY + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE); + } + _SEH2_END; + } + + return TRUE; }
/* @@ -999,11 +738,8 @@ CcZeroData ( NTSTATUS Status; LARGE_INTEGER WriteOffset; LONGLONG Length; - ULONG CurrentLength; - PMDL Mdl; - ULONG i; - IO_STATUS_BLOCK Iosb; - KEVENT Event; + PROS_VACB Vacb; + PROS_SHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait); @@ -1015,9 +751,14 @@ CcZeroData ( Length = EndOffset->QuadPart - StartOffset->QuadPart; WriteOffset.QuadPart = StartOffset->QuadPart;
- if (FileObject->SectionObjectPointer->SharedCacheMap == NULL) + if (!SharedCacheMap || (FileObject->Flags & FO_WRITE_THROUGH)) { - /* File is not cached */ + /* Make this a non-cached write */ + IO_STATUS_BLOCK Iosb; + KEVENT Event; + PMDL Mdl; + ULONG i; + ULONG CurrentLength;
Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
@@ -1032,7 +773,7 @@ CcZeroData ( CurrentLength = Length; } MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength); - Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ); + Mdl->MdlFlags |= MDL_PAGES_LOCKED; for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++) { ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage; @@ -1055,18 +796,42 @@ CcZeroData ( WriteOffset.QuadPart += CurrentLength; Length -= CurrentLength; } + + return TRUE; } - else + + ASSERT(EndOffset->QuadPart <= SharedCacheMap->FileSize.QuadPart); + + while(WriteOffset.QuadPart < EndOffset->QuadPart) { - IO_STATUS_BLOCK IoStatus; + ULONG VacbOffset = WriteOffset.QuadPart % VACB_MAPPING_GRANULARITY; + ULONG VacbLength = min(Length, VACB_MAPPING_GRANULARITY - VacbOffset);
- return CcCopyData(FileObject, - WriteOffset.QuadPart, - NULL, - Length, - CcOperationZero, - Wait, - &IoStatus); + Status = CcRosGetVacb(SharedCacheMap, WriteOffset.QuadPart, &Vacb); + if (!NT_SUCCESS(Status)) + { + ExRaiseStatus(Status); + return FALSE; + } + + _SEH2_TRY + { + if (!CcRosEnsureVacbResident(Vacb, Wait, FALSE, VacbOffset, VacbLength)) + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); + return FALSE; + } + + RtlZeroMemory((PVOID)((ULONG_PTR)Vacb->BaseAddress + VacbOffset), VacbLength); + + WriteOffset.QuadPart += VacbLength; + Length -= VacbLength; + } + _SEH2_FINALLY + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE); + } + _SEH2_END; }
return TRUE; diff --git a/ntoskrnl/cc/fs.c b/ntoskrnl/cc/fs.c index 5798f56a91a..5a74ecee48c 100644 --- a/ntoskrnl/cc/fs.c +++ b/ntoskrnl/cc/fs.c @@ -10,13 +10,10 @@ /* INCLUDES ******************************************************************/
#include <ntoskrnl.h> + #define NDEBUG #include <debug.h>
-/* GLOBALS *****************************************************************/ - -NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb); - /* FUNCTIONS *****************************************************************/
/* @@ -272,8 +269,9 @@ CcSetFileSizes ( IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes) { - KIRQL oldirql; + KIRQL OldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap; + LARGE_INTEGER OldSectionSize;
CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n", FileObject, FileSizes); @@ -294,7 +292,14 @@ CcSetFileSizes ( if (SharedCacheMap == NULL) return;
- if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart) + /* Update the relevant fields */ + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); + OldSectionSize = SharedCacheMap->SectionSize; + SharedCacheMap->SectionSize = FileSizes->AllocationSize; + SharedCacheMap->FileSize = FileSizes->FileSize; + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); + + if (FileSizes->AllocationSize.QuadPart < OldSectionSize.QuadPart) { CcPurgeCacheSection(FileObject->SectionObjectPointer, &FileSizes->AllocationSize, @@ -303,46 +308,9 @@ CcSetFileSizes ( } else { - PROS_VACB LastVacb; - - /* - * If file (allocation) size has increased, then we need to check whether - * it just grows in a single VACB (the last one). - * If so, we must mark the VACB as invalid to trigger a read to the - * FSD at the next VACB usage, and thus avoid returning garbage - */ - - /* Check for allocation size and the last VACB */ - if (SharedCacheMap->SectionSize.QuadPart < FileSizes->AllocationSize.QuadPart && - SharedCacheMap->SectionSize.QuadPart % VACB_MAPPING_GRANULARITY) - { - LastVacb = CcRosLookupVacb(SharedCacheMap, - SharedCacheMap->SectionSize.QuadPart); - if (LastVacb != NULL) - { - /* Mark it as invalid */ - CcRosReleaseVacb(SharedCacheMap, LastVacb, LastVacb->Dirty ? LastVacb->Valid : FALSE, FALSE, FALSE); - } - } - - /* Check for file size and the last VACB */ - if (SharedCacheMap->FileSize.QuadPart < FileSizes->FileSize.QuadPart && - SharedCacheMap->FileSize.QuadPart % VACB_MAPPING_GRANULARITY) - { - LastVacb = CcRosLookupVacb(SharedCacheMap, - SharedCacheMap->FileSize.QuadPart); - if (LastVacb != NULL) - { - /* Mark it as invalid */ - CcRosReleaseVacb(SharedCacheMap, LastVacb, LastVacb->Dirty ? LastVacb->Valid : FALSE, FALSE, FALSE); - } - } + /* Extend our section object */ + MmExtendSection(SharedCacheMap->Section, &SharedCacheMap->SectionSize); } - - KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql); - SharedCacheMap->SectionSize = FileSizes->AllocationSize; - SharedCacheMap->FileSize = FileSizes->FileSize; - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); }
/* diff --git a/ntoskrnl/cc/pin.c b/ntoskrnl/cc/pin.c index b839e71dafd..189ba480305 100644 --- a/ntoskrnl/cc/pin.c +++ b/ntoskrnl/cc/pin.c @@ -67,91 +67,6 @@ CcpFindBcb( return (Found ? Bcb : NULL); }
-static -BOOLEAN -NTAPI -CcpMapData( - IN PROS_SHARED_CACHE_MAP SharedCacheMap, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG Flags, - OUT PROS_VACB *pVacb, - OUT PVOID *pBuffer) -{ - LONGLONG ReadOffset, BaseOffset; - BOOLEAN Valid; - PROS_VACB Vacb; - NTSTATUS Status; - LONGLONG ROffset; - - ReadOffset = FileOffset->QuadPart; - - DPRINT("SectionSize %I64x, FileSize %I64x\n", - SharedCacheMap->SectionSize.QuadPart, - SharedCacheMap->FileSize.QuadPart); - - if (ReadOffset % VACB_MAPPING_GRANULARITY + Length > VACB_MAPPING_GRANULARITY) - { - CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", - SharedCacheMap->FileObject, FileOffset, Length, Flags); - return FALSE; - } - - if (!BooleanFlagOn(Flags, MAP_NO_READ)) - { - static int Warned = 0; - - SetFlag(Flags, MAP_NO_READ); - if (!Warned) - { - DPRINT1("Mapping/pinning with no read not implemented. Forcing read, might fail if wait not allowed\n"); - Warned++; - } - } - - /* Properly round offset and call internal helper for getting a VACB */ - ROffset = ROUND_DOWN(ReadOffset, VACB_MAPPING_GRANULARITY); - Status = CcRosGetVacb(SharedCacheMap, - ROffset, - &BaseOffset, - pBuffer, - &Valid, - &Vacb); - if (!NT_SUCCESS(Status)) - { - CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", - SharedCacheMap->FileObject, FileOffset, Length, Flags); - ExRaiseStatus(Status); - return FALSE; - } - - if (!Valid && BooleanFlagOn(Flags, MAP_NO_READ)) - { - if (!BooleanFlagOn(Flags, MAP_WAIT)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", - SharedCacheMap->FileObject, FileOffset, Length, Flags); - return FALSE; - } - - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", - SharedCacheMap->FileObject, FileOffset, Length, Flags); - ExRaiseStatus(Status); - return FALSE; - } - } - - *pBuffer = (PUCHAR)*pBuffer + ReadOffset % VACB_MAPPING_GRANULARITY; - *pVacb = Vacb; - - return TRUE; -} - static VOID CcpDereferenceBcb( @@ -304,44 +219,44 @@ CcpPinData( OUT PVOID * Buffer) { PINTERNAL_BCB NewBcb; - BOOLEAN Result; - PROS_VACB Vacb; KIRQL OldIrql; - ULONG MapFlags; + ULONG VacbOffset; + NTSTATUS Status; + BOOLEAN Result; + + VacbOffset = (ULONG)(FileOffset->QuadPart % VACB_MAPPING_GRANULARITY); + /* This seems to be valid, according to KMTests */ + if ((VacbOffset + Length) > VACB_MAPPING_GRANULARITY) + Length = VACB_MAPPING_GRANULARITY - VacbOffset;
KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); NewBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, TRUE);
if (NewBcb != NULL) { + BOOLEAN Result; + ++NewBcb->RefCount; KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
if (BooleanFlagOn(Flags, PIN_EXCLUSIVE)) - { Result = ExAcquireResourceExclusiveLite(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); - } else - { Result = ExAcquireSharedStarveExclusive(&NewBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); - }
if (!Result) { CcpDereferenceBcb(SharedCacheMap, NewBcb); - NewBcb = NULL; - } - else - { - NewBcb->PinCount++; - *Bcb = NewBcb; - *Buffer = (PUCHAR)NewBcb->Vacb->BaseAddress + FileOffset->QuadPart % VACB_MAPPING_GRANULARITY; + return FALSE; }
- return Result; + NewBcb->PinCount++; } else { + LONGLONG ROffset; + PROS_VACB Vacb; + KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
if (BooleanFlagOn(Flags, PIN_IF_BCB)) @@ -349,29 +264,49 @@ CcpPinData( return FALSE; }
- MapFlags = Flags & PIN_WAIT; - if (BooleanFlagOn(Flags, PIN_NO_READ)) + /* Properly round offset and call internal helper for getting a VACB */ + ROffset = ROUND_DOWN(FileOffset->QuadPart, VACB_MAPPING_GRANULARITY); + Status = CcRosGetVacb(SharedCacheMap, ROffset, &Vacb); + if (!NT_SUCCESS(Status)) { - SetFlag(MapFlags, MAP_NO_READ); + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", + SharedCacheMap->FileObject, FileOffset, Length, Flags); + ExRaiseStatus(Status); + return FALSE; }
- Result = CcpMapData(SharedCacheMap, FileOffset, Length, MapFlags, &Vacb, Buffer); - if (Result) + NewBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, Flags, TRUE); + if (NewBcb == NULL) { - NewBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, Flags, TRUE); - if (NewBcb == NULL) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); - Result = FALSE; - } - else - { - *Bcb = NewBcb; - } + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); + return FALSE; } }
- return Result; + Result = FALSE; + _SEH2_TRY + { + /* Ensure the pages are resident */ + Result = CcRosEnsureVacbResident(NewBcb->Vacb, + BooleanFlagOn(Flags, PIN_WAIT), + BooleanFlagOn(Flags, PIN_NO_READ), + VacbOffset, Length); + } + _SEH2_FINALLY + { + if (!Result) + { + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", + SharedCacheMap->FileObject, FileOffset, Length, Flags); + CcUnpinData(NewBcb); + return FALSE; + } + } + _SEH2_END; + + *Bcb = NewBcb; + *Buffer = (PVOID)((ULONG_PTR)NewBcb->Vacb->BaseAddress + VacbOffset); + return TRUE; }
/* @@ -387,13 +322,15 @@ CcMapData ( OUT PVOID *pBcb, OUT PVOID *pBuffer) { - BOOLEAN Ret; KIRQL OldIrql; PINTERNAL_BCB iBcb; PROS_VACB Vacb; PROS_SHARED_CACHE_MAP SharedCacheMap; + ULONG VacbOffset; + NTSTATUS Status; + BOOLEAN Result;
- DPRINT("CcMapData(FileObject 0x%p, FileOffset %I64x, Length %lu, Flags 0x%lx," + CCTRACE(CC_API_DEBUG, "CcMapData(FileObject 0x%p, FileOffset 0x%I64x, Length %lu, Flags 0x%lx," " pBcb 0x%p, pBuffer 0x%p)\n", FileObject, FileOffset->QuadPart, Length, Flags, pBcb, pBuffer);
@@ -413,6 +350,11 @@ CcMapData ( ++CcMapDataNoWait; }
+ VacbOffset = (ULONG)(FileOffset->QuadPart % VACB_MAPPING_GRANULARITY); + /* KMTests seem to show that it is allowed to call accross mapping granularity */ + if ((VacbOffset + Length) > VACB_MAPPING_GRANULARITY) + Length = VACB_MAPPING_GRANULARITY - VacbOffset; + KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); iBcb = CcpFindBcb(SharedCacheMap, FileOffset, Length, FALSE);
@@ -420,34 +362,54 @@ CcMapData ( { KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
- Ret = CcpMapData(SharedCacheMap, FileOffset, Length, Flags, &Vacb, pBuffer); - if (Ret) + /* Call internal helper for getting a VACB */ + Status = CcRosGetVacb(SharedCacheMap, FileOffset->QuadPart, &Vacb); + if (!NT_SUCCESS(Status)) { - iBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, 0, FALSE); - if (iBcb == NULL) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); - Ret = FALSE; - } - else - { - *pBcb = iBcb; - } + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", + SharedCacheMap->FileObject, FileOffset, Length, Flags); + ExRaiseStatus(Status); + return FALSE; + } + + iBcb = CcpGetAppropriateBcb(SharedCacheMap, Vacb, FileOffset, Length, 0, FALSE); + if (iBcb == NULL) + { + CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", + SharedCacheMap->FileObject, FileOffset, Length, Flags); + return FALSE; } } else { ++iBcb->RefCount; KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); + }
- *pBcb = iBcb; - *pBuffer = (PUCHAR)iBcb->Vacb->BaseAddress + FileOffset->QuadPart % VACB_MAPPING_GRANULARITY; - Ret = TRUE; + _SEH2_TRY + { + Result = FALSE; + /* Ensure the pages are resident */ + Result = CcRosEnsureVacbResident(iBcb->Vacb, BooleanFlagOn(Flags, MAP_WAIT), + BooleanFlagOn(Flags, MAP_NO_READ), VacbOffset, Length); + } + _SEH2_FINALLY + { + if (!Result) + { + CcpDereferenceBcb(SharedCacheMap, iBcb); + return FALSE; + } } + _SEH2_END; + + *pBcb = iBcb; + *pBuffer = (PVOID)((ULONG_PTR)iBcb->Vacb->BaseAddress + VacbOffset);
- CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> %d Bcb=%p\n", - FileObject, FileOffset, Length, Flags, Ret, *pBcb); - return Ret; + CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> TRUE Bcb=%p, Buffer %p\n", + FileObject, FileOffset, Length, Flags, *pBcb, *pBuffer); + return Result; }
/* diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index adb28bb84ab..ddbe77e22af 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -156,20 +156,29 @@ CcRosTraceCacheMap ( #endif }
+NTSTATUS +NTAPI +MmFlushVirtualMemory(IN PEPROCESS Process, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T RegionSize, + OUT PIO_STATUS_BLOCK IoStatusBlock); + NTSTATUS NTAPI CcRosFlushVacb ( PROS_VACB Vacb) { + IO_STATUS_BLOCK Iosb; + SIZE_T FlushSize = min(VACB_MAPPING_GRANULARITY, + Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart); NTSTATUS Status;
CcRosUnmarkDirtyVacb(Vacb, TRUE);
- Status = CcWriteVirtualAddress(Vacb); + Status = MmFlushVirtualMemory(NULL, &Vacb->BaseAddress, &FlushSize, &Iosb); + if (!NT_SUCCESS(Status)) - { CcRosMarkDirtyVacb(Vacb); - }
return Status; } @@ -234,6 +243,8 @@ CcRosFlushDirtyPages ( current->SharedCacheMap->LazyWriteContext, Wait); if (!Locked) { + DPRINT("Not locked!"); + ASSERT(!Wait); OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); CcRosVacbDecRefCount(current); continue; @@ -264,15 +275,18 @@ CcRosFlushDirtyPages ( PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE; (*Count) += PagesFreed;
- /* Make sure we don't overflow target! */ - if (Target < PagesFreed) + if (!Wait) { - /* If we would have, jump to zero directly */ - Target = 0; - } - else - { - Target -= PagesFreed; + /* Make sure we don't overflow target! */ + if (Target < PagesFreed) + { + /* If we would have, jump to zero directly */ + Target = 0; + } + else + { + Target -= PagesFreed; + } } }
@@ -286,136 +300,6 @@ CcRosFlushDirtyPages ( return STATUS_SUCCESS; }
-NTSTATUS -CcRosTrimCache ( - ULONG Target, - ULONG Priority, - PULONG NrFreed) -/* - * FUNCTION: Try to free some memory from the file cache. - * ARGUMENTS: - * Target - The number of pages to be freed. - * Priority - The priority of free (currently unused). - * NrFreed - Points to a variable where the number of pages - * actually freed is returned. - */ -{ - PLIST_ENTRY current_entry; - PROS_VACB current; - ULONG PagesFreed; - KIRQL oldIrql; - LIST_ENTRY FreeList; - PFN_NUMBER Page; - ULONG i; - BOOLEAN FlushedPages = FALSE; - - DPRINT("CcRosTrimCache(Target %lu)\n", Target); - - InitializeListHead(&FreeList); - - *NrFreed = 0; - -retry: - oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - - current_entry = VacbLruListHead.Flink; - while (current_entry != &VacbLruListHead) - { - ULONG Refs; - - current = CONTAINING_RECORD(current_entry, - ROS_VACB, - VacbLruListEntry); - current_entry = current_entry->Flink; - - KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock); - - /* Reference the VACB */ - CcRosVacbIncRefCount(current); - - /* Check if it's mapped and not dirty */ - if (InterlockedCompareExchange((PLONG)¤t->MappedCount, 0, 0) > 0 && !current->Dirty) - { - /* We have to break these locks because Cc sucks */ - KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock); - KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); - - /* Page out the VACB */ - for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++) - { - Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT); - - MmPageOutPhysicalAddress(Page); - } - - /* Reacquire the locks */ - oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock); - } - - /* Dereference the VACB */ - Refs = CcRosVacbDecRefCount(current); - - /* Check if we can free this entry now */ - if (Refs < 2) - { - ASSERT(!current->Dirty); - ASSERT(!current->MappedCount); - ASSERT(Refs == 1); - - RemoveEntryList(¤t->CacheMapVacbListEntry); - RemoveEntryList(¤t->VacbLruListEntry); - InitializeListHead(¤t->VacbLruListEntry); - InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); - - /* Calculate how many pages we freed for Mm */ - PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target); - Target -= PagesFreed; - (*NrFreed) += PagesFreed; - } - - KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock); - } - - KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); - - /* Try flushing pages if we haven't met our target */ - if ((Target > 0) && !FlushedPages) - { - /* Flush dirty pages to disk */ - CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); - FlushedPages = TRUE; - - /* We can only swap as many pages as we flushed */ - if (PagesFreed < Target) Target = PagesFreed; - - /* Check if we flushed anything */ - if (PagesFreed != 0) - { - /* Try again after flushing dirty pages */ - DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed); - goto retry; - } - } - - while (!IsListEmpty(&FreeList)) - { - ULONG Refs; - - current_entry = RemoveHeadList(&FreeList); - current = CONTAINING_RECORD(current_entry, - ROS_VACB, - CacheMapVacbListEntry); - InitializeListHead(¤t->CacheMapVacbListEntry); - Refs = CcRosVacbDecRefCount(current); - ASSERT(Refs == 0); - } - - DPRINT("Evicted %lu cache pages\n", (*NrFreed)); - - return STATUS_SUCCESS; -} - NTSTATUS NTAPI CcRosReleaseVacb ( @@ -504,6 +388,7 @@ CcRosMarkDirtyVacb ( { KIRQL oldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap; + ULONG Length = VACB_MAPPING_GRANULARITY;
SharedCacheMap = Vacb->SharedCacheMap;
@@ -513,8 +398,12 @@ CcRosMarkDirtyVacb ( ASSERT(!Vacb->Dirty);
InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; - Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; +#if 0 + if (Vacb->FileOffset.QuadPart + Length > SharedCacheMap->SectionSize.QuadPart) + Length = SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart; +#endif + CcTotalDirtyPages += PAGE_ROUND_UP(Length) / PAGE_SIZE; + Vacb->SharedCacheMap->DirtyPages += PAGE_ROUND_UP(Length) / PAGE_SIZE; CcRosVacbIncRefCount(Vacb);
/* Move to the tail of the LRU list */ @@ -531,6 +420,9 @@ CcRosMarkDirtyVacb ( CcScheduleLazyWriteScan(FALSE); } KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); + + /* Tell Mm */ + MmMakePagesDirty(NULL, Vacb->BaseAddress, Length); }
VOID @@ -541,6 +433,7 @@ CcRosUnmarkDirtyVacb ( { KIRQL oldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap; + ULONG Length = VACB_MAPPING_GRANULARITY;
SharedCacheMap = Vacb->SharedCacheMap;
@@ -556,8 +449,14 @@ CcRosUnmarkDirtyVacb (
RemoveEntryList(&Vacb->DirtyVacbListEntry); InitializeListHead(&Vacb->DirtyVacbListEntry); - CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; - Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + +#if 0 + if (Vacb->FileOffset.QuadPart + Length > SharedCacheMap->SectionSize.QuadPart) + Length = SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart; +#endif + CcTotalDirtyPages -= PAGE_ROUND_UP(Length) / PAGE_SIZE; + Vacb->SharedCacheMap->DirtyPages -= PAGE_ROUND_UP(Length) / PAGE_SIZE; + CcRosVacbDecRefCount(Vacb);
if (LockViews) @@ -626,73 +525,6 @@ CcRosUnmapVacb ( return STATUS_SUCCESS; }
-static -NTSTATUS -CcRosMapVacbInKernelSpace( - PROS_VACB Vacb) -{ - ULONG i; - NTSTATUS Status; - ULONG_PTR NumberOfPages; - PVOID BaseAddress = NULL; - - /* Create a memory area. */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), - 0, // nothing checks for VACB mareas, so set to 0 - &BaseAddress, - VACB_MAPPING_GRANULARITY, - PAGE_READWRITE, - (PMEMORY_AREA*)&Vacb->MemoryArea, - 0, - PAGE_SIZE); - ASSERT(Vacb->BaseAddress == NULL); - Vacb->BaseAddress = BaseAddress; - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status, Vacb); - return Status; - } - - ASSERT(((ULONG_PTR)Vacb->BaseAddress % PAGE_SIZE) == 0); - ASSERT((ULONG_PTR)Vacb->BaseAddress > (ULONG_PTR)MmSystemRangeStart); - ASSERT((ULONG_PTR)Vacb->BaseAddress + VACB_MAPPING_GRANULARITY - 1 > (ULONG_PTR)MmSystemRangeStart); - - /* Create a virtual mapping for this memory area */ - NumberOfPages = BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY); - for (i = 0; i < NumberOfPages; i++) - { - PFN_NUMBER PageFrameNumber; - - MI_SET_USAGE(MI_USAGE_CACHE); - Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &PageFrameNumber); - if (PageFrameNumber == 0) - { - DPRINT1("Unable to allocate page\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - - ASSERT(BaseAddress == Vacb->BaseAddress); - ASSERT(i * PAGE_SIZE < VACB_MAPPING_GRANULARITY); - ASSERT((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE) >= (ULONG_PTR)BaseAddress); - ASSERT((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE) > (ULONG_PTR)MmSystemRangeStart); - - Status = MmCreateVirtualMapping(NULL, - (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE)), - PAGE_READWRITE, - &PageFrameNumber, - 1); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to create virtual mapping\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - } - - return STATUS_SUCCESS; -} - static BOOLEAN CcRosFreeUnusedVacb ( @@ -789,6 +621,7 @@ CcRosCreateVacb ( KIRQL oldIrql; ULONG Refs; BOOLEAN Retried; + SIZE_T ViewSize = VACB_MAPPING_GRANULARITY;
ASSERT(SharedCacheMap);
@@ -823,8 +656,9 @@ CcRosCreateVacb (
Retried = FALSE; Retry: - /* Map VACB in kernel space */ - Status = CcRosMapVacbInKernelSpace(current); + /* Map VACB in system space */ + Status = MmMapViewInSystemSpaceEx(SharedCacheMap->Section, ¤t->BaseAddress, &ViewSize, ¤t->FileOffset); + if (!NT_SUCCESS(Status)) { ULONG Freed; @@ -932,14 +766,50 @@ Retry: return Status; }
+BOOLEAN +NTAPI +CcRosEnsureVacbResident( + _In_ PROS_VACB Vacb, + _In_ BOOLEAN Wait, + _In_ BOOLEAN NoRead, + _In_ ULONG Offset, + _In_ ULONG Length +) +{ + PVOID BaseAddress; + + ASSERT((Offset + Length) <= VACB_MAPPING_GRANULARITY); + + if ((Vacb->FileOffset.QuadPart + Offset) > Vacb->SharedCacheMap->FileSize.QuadPart) + return FALSE; + + BaseAddress = (PVOID)((ULONG_PTR)Vacb->BaseAddress + Offset); + + /* Check if the pages are resident */ + if (!MmArePagesResident(NULL, BaseAddress, Length)) + { + if (!Wait) + { + return FALSE; + } + + if (!NoRead) + { + NTSTATUS Status = MmMakePagesResident(NULL, BaseAddress, Length); + if (!NT_SUCCESS(Status)) + ExRaiseStatus(Status); + } + } + + return TRUE; +} + + NTSTATUS NTAPI CcRosGetVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, - PLONGLONG BaseOffset, - PVOID* BaseAddress, - PBOOLEAN UptoDate, PROS_VACB *Vacb) { PROS_VACB current; @@ -978,13 +848,9 @@ CcRosGetVacb ( KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
/* - * Return information about the VACB to the caller. + * Return the VACB to the caller. */ - *UptoDate = current->Valid; - *BaseAddress = current->BaseAddress; - DPRINT("*BaseAddress %p\n", *BaseAddress); *Vacb = current; - *BaseOffset = current->FileOffset.QuadPart;
ASSERT(Refs > 1);
@@ -996,14 +862,11 @@ NTAPI CcRosRequestVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, - PVOID* BaseAddress, - PBOOLEAN UptoDate, PROS_VACB *Vacb) /* * FUNCTION: Request a page mapping for a shared cache map */ { - LONGLONG BaseOffset;
ASSERT(SharedCacheMap);
@@ -1016,30 +879,9 @@ CcRosRequestVacb (
return CcRosGetVacb(SharedCacheMap, FileOffset, - &BaseOffset, - BaseAddress, - UptoDate, Vacb); }
-static -VOID -CcFreeCachePage ( - PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_NUMBER Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page != 0) - { - ASSERT(MmGetReferenceCountPage(Page) == 1); - MmReleasePageMemoryConsumer(MC_CACHE, Page); - } -} - NTSTATUS CcRosInternalFreeVacb ( PROS_VACB Vacb) @@ -1047,6 +889,8 @@ CcRosInternalFreeVacb ( * FUNCTION: Releases a VACB associated with a shared cache map */ { + NTSTATUS Status; + DPRINT("Freeing VACB 0x%p\n", Vacb); #if DBG if (Vacb->SharedCacheMap->Trace) @@ -1055,12 +899,14 @@ CcRosInternalFreeVacb ( } #endif
- MmLockAddressSpace(MmGetKernelAddressSpace()); - MmFreeMemoryArea(MmGetKernelAddressSpace(), - Vacb->MemoryArea, - CcFreeCachePage, - NULL); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); + /* Delete the mapping */ + Status = MmUnmapViewInSystemSpace(Vacb->BaseAddress); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to unmap VACB from System address space! Status 0x%08X\n", Status); + ASSERT(FALSE); + /* Proceed with the deĺetion anyway */ + }
if (Vacb->ReferenceCount != 0) { @@ -1097,11 +943,8 @@ CcFlushCache ( PROS_VACB current; NTSTATUS Status;
- CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n", - SectionObjectPointers, FileOffset, Length); - - DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n", - SectionObjectPointers, FileOffset, Length, IoStatus); + CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=0x%I64X Length=%lu\n", + SectionObjectPointers, FileOffset ? FileOffset->QuadPart : 0LL, Length);
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) { @@ -1217,6 +1060,8 @@ CcRosDeleteFileCache ( KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);
KeReleaseQueuedSpinLock(LockQueueMasterLock, *OldIrql); + if(SharedCacheMap->Section) + ObDereferenceObject(SharedCacheMap->Section); ObDereferenceObject(SharedCacheMap->FileObject);
while (!IsListEmpty(&FreeList)) @@ -1299,36 +1144,6 @@ CcRosRemoveIfClosed ( KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); }
- -VOID -NTAPI -CcRosDereferenceCache ( - PFILE_OBJECT FileObject) -{ - PROS_SHARED_CACHE_MAP SharedCacheMap; - KIRQL OldIrql; - - OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - ASSERT(SharedCacheMap); - if (SharedCacheMap->OpenCount > 0) - { - SharedCacheMap->OpenCount--; - if (SharedCacheMap->OpenCount == 0) - { - KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); - MmFreeSectionSegments(SharedCacheMap->FileObject); - - OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - CcRosDeleteFileCache(FileObject, SharedCacheMap, &OldIrql); - KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); - - return; - } - } - KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); -} - NTSTATUS NTAPI CcRosReleaseFileCache ( @@ -1373,20 +1188,12 @@ CcRosReleaseFileCache ( PrivateMap->NodeTypeCode = 0; }
- if (SharedCacheMap->OpenCount > 0) - { - SharedCacheMap->OpenCount--; - if (SharedCacheMap->OpenCount == 0) - { - KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); - MmFreeSectionSegments(SharedCacheMap->FileObject); - - OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - CcRosDeleteFileCache(FileObject, SharedCacheMap, &OldIrql); - KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + ASSERT(SharedCacheMap->OpenCount > 0);
- return STATUS_SUCCESS; - } + SharedCacheMap->OpenCount--; + if (SharedCacheMap->OpenCount == 0) + { + CcRosDeleteFileCache(FileObject, SharedCacheMap, &OldIrql); } } } @@ -1412,6 +1219,8 @@ CcRosInitializeFileCache (
DPRINT("CcRosInitializeFileCache(FileObject 0x%p)\n", FileObject);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + Allocated = FALSE; SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; if (SharedCacheMap == NULL) @@ -1437,27 +1246,37 @@ CcRosInitializeFileCache ( KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); InitializeListHead(&SharedCacheMap->BcbList); - }
- OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); - if (Allocated) + SharedCacheMap->Flags = SHARED_CACHE_MAP_IN_CREATION; + + ObReferenceObjectByPointer(FileObject, + FILE_ALL_ACCESS, + NULL, + KernelMode); + + FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; + + // CcRosTraceCacheMap(SharedCacheMap, TRUE); + } + else if (SharedCacheMap->Flags & SHARED_CACHE_MAP_IN_CREATION) { - if (FileObject->SectionObjectPointer->SharedCacheMap == NULL) - { - ObReferenceObjectByPointer(FileObject, - FILE_ALL_ACCESS, - NULL, - KernelMode); - FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; + /* The shared cache map is being created somewhere else. Wait for that to happen */ + KEVENT Waiter; + PKEVENT PreviousWaiter = SharedCacheMap->CreateEvent;
- InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks); - } - else - { - ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - } + KeInitializeEvent(&Waiter, NotificationEvent, FALSE); + SharedCacheMap->CreateEvent = &Waiter; + + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + + KeWaitForSingleObject(&Waiter, Executive, KernelMode, FALSE, NULL); + + if (PreviousWaiter) + KeSetEvent(PreviousWaiter, IO_NO_INCREMENT, FALSE); + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); } + if (FileObject->PrivateCacheMap == NULL) { PPRIVATE_CACHE_MAP PrivateMap; @@ -1503,8 +1322,48 @@ CcRosInitializeFileCache ( FileObject->PrivateCacheMap = PrivateMap; SharedCacheMap->OpenCount++; } + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
+ /* Create the section */ + if (Allocated) + { + NTSTATUS Status; + + ASSERT(SharedCacheMap->Section == NULL); + + Status = MmCreateSection( + &SharedCacheMap->Section, + SECTION_ALL_ACCESS, + NULL, + &SharedCacheMap->SectionSize, + PAGE_READWRITE, + 0, + NULL, + FileObject); + + ASSERT(NT_SUCCESS(Status)); + + if (!NT_SUCCESS(Status)) + { + CcRosReleaseFileCache(FileObject); + return Status; + } + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + + InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks); + SharedCacheMap->Flags &= ~SHARED_CACHE_MAP_IN_CREATION; + + if (SharedCacheMap->CreateEvent) + { + KeSetEvent(SharedCacheMap->CreateEvent, IO_NO_INCREMENT, FALSE); + SharedCacheMap->CreateEvent = NULL; + } + + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + } + return STATUS_SUCCESS; }
@@ -1564,8 +1423,6 @@ CcInitView ( TAG_VACB, 20);
- MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); - CcInitCacheZeroPage(); }
diff --git a/ntoskrnl/ex/init.c b/ntoskrnl/ex/init.c index 8eb867b09cd..fc98cccd430 100644 --- a/ntoskrnl/ex/init.c +++ b/ntoskrnl/ex/init.c @@ -1970,7 +1970,6 @@ Phase1InitializationDiscard(IN PVOID Context) InbvEnableDisplayString(TRUE);
/* Launch initial process */ - DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed); ProcessInfo = &InitBuffer->ProcessInfo; ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
@@ -2009,7 +2008,6 @@ Phase1InitializationDiscard(IN PVOID Context)
/* Free the boot buffer */ ExFreePoolWithTag(InitBuffer, TAG_INIT); - DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed); }
VOID diff --git a/ntoskrnl/ex/sysinfo.c b/ntoskrnl/ex/sysinfo.c index 64cbffc5ba1..f595623b4c8 100644 --- a/ntoskrnl/ex/sysinfo.c +++ b/ntoskrnl/ex/sysinfo.c @@ -719,7 +719,6 @@ QSI_DEF(SystemPerformanceInformation) * Not sure this is right. 8^\ */ Spi->CommittedPages = MiMemoryConsumers[MC_SYSTEM].PagesUsed + - MiMemoryConsumers[MC_CACHE].PagesUsed + MiMemoryConsumers[MC_USER].PagesUsed + MiUsedSwapPages; /* @@ -767,7 +766,7 @@ QSI_DEF(SystemPerformanceInformation) Spi->TotalSystemDriverPages = 0; /* FIXME */ Spi->Spare3Count = 0; /* FIXME */
- Spi->ResidentSystemCachePage = MiMemoryConsumers[MC_CACHE].PagesUsed; + Spi->ResidentSystemCachePage = 0; /* FIXME */ Spi->ResidentPagedPoolPage = 0; /* FIXME */
Spi->ResidentSystemDriverPage = 0; /* FIXME */ @@ -1477,13 +1476,10 @@ QSI_DEF(SystemFileCacheInformation) RtlZeroMemory(Sci, sizeof(SYSTEM_FILECACHE_INFORMATION));
/* Return the Byte size not the page size. */ - Sci->CurrentSize = - MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; - Sci->PeakSize = - MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */ + Sci->CurrentSize = 0; /* FIXME */ + Sci->PeakSize = 0; /* FIXME */ /* Taskmgr multiplies this one by page size right away */ - Sci->CurrentSizeIncludingTransitionInPages = - MiMemoryConsumers[MC_CACHE].PagesUsed; /* FIXME: Should be */ + Sci->CurrentSizeIncludingTransitionInPages = 0; /* FIXME: Should be */ /* system working set and standby pages. */ Sci->PageFaultCount = 0; /* FIXME */ Sci->MinimumWorkingSet = 0; /* FIXME */ diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 18c0b9effa2..9e186a61d11 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -3,7 +3,7 @@ // // Define this if you want debugging support // -#define _CC_DEBUG_ 0x00 +#define _CC_DEBUG_ 0x0
// // These define the Debug Masks Supported @@ -179,6 +179,8 @@ typedef struct _ROS_SHARED_CACHE_MAP ULONG DirtyPages; LIST_ENTRY SharedCacheMapLinks; ULONG Flags; + PVOID Section; + PKEVENT CreateEvent; PCACHE_MANAGER_CALLBACKS Callbacks; PVOID LazyWriteContext; LIST_ENTRY PrivateList; @@ -197,13 +199,12 @@ typedef struct _ROS_SHARED_CACHE_MAP
#define READAHEAD_DISABLED 0x1 #define WRITEBEHIND_DISABLED 0x2 +#define SHARED_CACHE_MAP_IN_CREATION 0x4
typedef struct _ROS_VACB { /* Base address of the region where the view's data is mapped. */ PVOID BaseAddress; - /* Memory area representing the region where the view's data is mapped. */ - struct _MEMORY_AREA* MemoryArea; /* Are the contents of the view valid. */ BOOLEAN Valid; /* Are the contents of the view newer than those on disk. */ @@ -316,12 +317,19 @@ NTAPI CcRosGetVacb( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, - PLONGLONG BaseOffset, - PVOID *BaseAddress, - PBOOLEAN UptoDate, PROS_VACB *Vacb );
+BOOLEAN +NTAPI +CcRosEnsureVacbResident( + _In_ PROS_VACB Vacb, + _In_ BOOLEAN Wait, + _In_ BOOLEAN NoRead, + _In_ ULONG Offset, + _In_ ULONG Length +); + VOID NTAPI CcInitView(VOID); @@ -330,14 +338,6 @@ VOID NTAPI CcShutdownLazyWriter(VOID);
-NTSTATUS -NTAPI -CcReadVirtualAddress(PROS_VACB Vacb); - -NTSTATUS -NTAPI -CcWriteVirtualAddress(PROS_VACB Vacb); - BOOLEAN NTAPI CcInitializeCacheManager(VOID); @@ -415,8 +415,6 @@ NTAPI CcRosRequestVacb( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, - PVOID* BaseAddress, - PBOOLEAN UptoDate, PROS_VACB *Vacb );
diff --git a/ntoskrnl/include/internal/mm.h b/ntoskrnl/include/internal/mm.h index be8b0acc4b0..55e9fcfc29c 100644 --- a/ntoskrnl/include/internal/mm.h +++ b/ntoskrnl/include/internal/mm.h @@ -89,12 +89,9 @@ typedef ULONG_PTR SWAPENTRY;
#define SEC_PHYSICALMEMORY (0x80000000)
-#define MM_DATAFILE_SEGMENT (0x2) - -#define MC_CACHE (0) -#define MC_USER (1) -#define MC_SYSTEM (2) -#define MC_MAXIMUM (3) +#define MC_USER (0) +#define MC_SYSTEM (1) +#define MC_MAXIMUM (2)
#define PAGED_POOL_MASK 1 #define MUST_SUCCEED_POOL_MASK 2 @@ -171,10 +168,10 @@ typedef struct _MM_SECTION_SEGMENT FAST_MUTEX Lock; /* lock which protects the page directory */ LARGE_INTEGER RawLength; /* length of the segment which is part of the mapped file */ LARGE_INTEGER Length; /* absolute length of the segment */ - ULONG ReferenceCount; - ULONG CacheCount; + PULONG ReferenceCount; + ULONG SectionCount; ULONG Protection; - ULONG Flags; + PULONG Flags; BOOLEAN WriteCopy; BOOLEAN Locked;
@@ -185,6 +182,9 @@ typedef struct _MM_SECTION_SEGMENT ULONG Characteristics; } Image;
+ ULONG RefCount; + ULONG SegFlags; + LIST_ENTRY ListOfSegments; RTL_GENERIC_TABLE PageTable; } MM_SECTION_SEGMENT, *PMM_SECTION_SEGMENT; @@ -193,12 +193,20 @@ typedef struct _MM_IMAGE_SECTION_OBJECT { PFILE_OBJECT FileObject;
+ ULONG RefCount; + ULONG SegFlags; + SECTION_IMAGE_INFORMATION ImageInformation; PVOID BasedAddress; ULONG NrSegments; PMM_SECTION_SEGMENT Segments; } MM_IMAGE_SECTION_OBJECT, *PMM_IMAGE_SECTION_OBJECT;
+#define MM_DATAFILE_SEGMENT (0x2) +#define MM_SEGMENT_INDELETE (0x4) +#define MM_SEGMENT_INCREATE (0x8) + + #define MA_GetStartingAddress(_MemoryArea) ((_MemoryArea)->VadNode.StartingVpn << PAGE_SHIFT) #define MA_GetEndingAddress(_MemoryArea) (((_MemoryArea)->VadNode.EndingVpn + 1) << PAGE_SHIFT)
@@ -862,11 +870,6 @@ MmInitializeRmapList(VOID); VOID NTAPI MmSetCleanAllRmaps(PFN_NUMBER Page); - -VOID -NTAPI -MmSetDirtyAllRmaps(PFN_NUMBER Page); - BOOLEAN NTAPI MmIsDirtyPageRmap(PFN_NUMBER Page); @@ -1288,15 +1291,6 @@ MmNotPresentFaultSectionView( BOOLEAN Locked );
-NTSTATUS -NTAPI -MmPageOutSectionView( - PMMSUPPORT AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID Address, - ULONG_PTR Entry -); - NTSTATUS NTAPI MmCreatePhysicalMemorySection(VOID); @@ -1337,6 +1331,48 @@ MmMakePagesResident( _In_ PVOID Address, _In_ ULONG Length);
+NTSTATUS +NTAPI +MmMakePagesDirty( + _In_ PEPROCESS Process, + _In_ PVOID Address, + _In_ ULONG Length); + +NTSTATUS +NTAPI +MmRosFlushVirtualMemory( + _In_ PEPROCESS Process, + _Inout_ PVOID* Address, + _Inout_ PSIZE_T Length, + _Out_ PIO_STATUS_BLOCK Iosb); + +BOOLEAN +NTAPI +MmCheckDirtySegment( + PMM_SECTION_SEGMENT Segment, + PLARGE_INTEGER Offset, + BOOLEAN ForceDirty, + BOOLEAN PageOut); + +BOOLEAN +NTAPI +MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, + PMM_SECTION_SEGMENT Segment, + PLARGE_INTEGER Offset, + BOOLEAN Dirty, + BOOLEAN PageOut, + ULONG_PTR *InEntry); + +VOID +NTAPI +MmDereferenceSegment(PMM_SECTION_SEGMENT Segment); + +NTSTATUS +NTAPI +MmExtendSection( + _In_ PVOID Section, + _Inout_ PLARGE_INTEGER NewSize); + /* sysldr.c ******************************************************************/
VOID diff --git a/ntoskrnl/mm/ARM3/section.c b/ntoskrnl/mm/ARM3/section.c index 938a08d6037..9ea36637a22 100644 --- a/ntoskrnl/mm/ARM3/section.c +++ b/ntoskrnl/mm/ARM3/section.c @@ -2934,7 +2934,7 @@ MmMapViewOfArm3Section(IN PVOID SectionObject, if (!(*ViewSize)) { /* Compute it for the caller */ - CalculatedViewSize = Section->SizeOfSection.QuadPart - + CalculatedViewSize = Section->SizeOfSection.QuadPart - SectionOffset->QuadPart;
/* Check if it's larger than 4GB or overflows into kernel-mode */ @@ -3891,30 +3891,24 @@ NtExtendSection(IN HANDLE SectionHandle, NULL); if (!NT_SUCCESS(Status)) return Status;
- /* Really this should go in MmExtendSection */ - if (!Section->u.Flags.File || Section->u.Flags.Image) - { - DPRINT1("Not extending a file\n"); - ObDereferenceObject(Section); - return STATUS_SECTION_NOT_EXTENDED; - } - - /* FIXME: Do the work */ + Status = MmExtendSection(Section, &SafeNewMaximumSize);
/* Dereference the section */ ObDereferenceObject(Section);
- /* Enter SEH */ - _SEH2_TRY - { - /* Write back the new size */ - *NewMaximumSize = SafeNewMaximumSize; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + if (NT_SUCCESS(Status)) { - /* Nothing to do */ + _SEH2_TRY + { + /* Write back the new size */ + *NewMaximumSize = SafeNewMaximumSize; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; } - _SEH2_END;
/* Return the status */ return STATUS_NOT_IMPLEMENTED; diff --git a/ntoskrnl/mm/ARM3/virtual.c b/ntoskrnl/mm/ARM3/virtual.c index 19eb8a69b01..00271e03e7b 100644 --- a/ntoskrnl/mm/ARM3/virtual.c +++ b/ntoskrnl/mm/ARM3/virtual.c @@ -1356,12 +1356,8 @@ MmFlushVirtualMemory(IN PEPROCESS Process, OUT PIO_STATUS_BLOCK IoStatusBlock) { PAGED_CODE(); - UNIMPLEMENTED; - - // - // Fake success - // - return STATUS_SUCCESS; + /* For now we call the old Mm */ + return MmRosFlushVirtualMemory(Process, BaseAddress, RegionSize, IoStatusBlock); }
ULONG diff --git a/ntoskrnl/mm/ARM3/zeropage.c b/ntoskrnl/mm/ARM3/zeropage.c index 5fe22294199..80725e8a5a7 100644 --- a/ntoskrnl/mm/ARM3/zeropage.c +++ b/ntoskrnl/mm/ARM3/zeropage.c @@ -46,7 +46,7 @@ MmZeroPageThread(VOID) /* Get the discardable sections to free them */ MiFindInitializationCode(&StartAddress, &EndAddress); if (StartAddress) MiFreeInitializationCode(StartAddress, EndAddress); - DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed); + DPRINT("Free pages: %lx\n", MmAvailablePages);
/* Set our priority to 0 */ Thread->BasePriority = 0; diff --git a/ntoskrnl/mm/balance.c b/ntoskrnl/mm/balance.c index 5cd5e267a23..29c0dfc6f47 100644 --- a/ntoskrnl/mm/balance.c +++ b/ntoskrnl/mm/balance.c @@ -54,18 +54,6 @@ MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages) /* Set up targets. */ MiMinimumAvailablePages = 256; MiMinimumPagesPerRun = 256; - if ((NrAvailablePages + NrSystemPages) >= 8192) - { - MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 4 * 3; - } - else if ((NrAvailablePages + NrSystemPages) >= 4096) - { - MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 3 * 2; - } - else - { - MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 8; - } MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages - MiMinimumAvailablePages; }
diff --git a/ntoskrnl/mm/pagefile.c b/ntoskrnl/mm/pagefile.c index 37870520998..e0f9e087150 100644 --- a/ntoskrnl/mm/pagefile.c +++ b/ntoskrnl/mm/pagefile.c @@ -94,9 +94,6 @@ NTAPI MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages) { memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE)); - - /* FIXME: this flag should be set by the caller perhaps? */ - Mdl->MdlFlags |= MDL_IO_PAGE_READ; }
@@ -230,7 +227,7 @@ MiReadPageFile(
MmInitializeMdl(Mdl, NULL, PAGE_SIZE); MmBuildMdlFromPages(Mdl, &Page); - Mdl->MdlFlags |= MDL_PAGES_LOCKED; + Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ;
file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
diff --git a/ntoskrnl/mm/rmap.c b/ntoskrnl/mm/rmap.c index 9f5938d7496..d1cfb584dce 100644 --- a/ntoskrnl/mm/rmap.c +++ b/ntoskrnl/mm/rmap.c @@ -19,7 +19,6 @@ /* GLOBALS ******************************************************************/
static NPAGED_LOOKASIDE_LIST RmapLookasideList; -FAST_MUTEX RmapListLock;
/* FUNCTIONS ****************************************************************/
@@ -38,7 +37,6 @@ VOID NTAPI MmInitializeRmapList(VOID) { - ExInitializeFastMutex(&RmapListLock); ExInitializeNPagedLookasideList (&RmapLookasideList, NULL, RmapListFree, @@ -55,37 +53,27 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) PMM_RMAP_ENTRY entry; PMEMORY_AREA MemoryArea; PMMSUPPORT AddressSpace; - ULONG Type; PVOID Address; PEPROCESS Process; - ULONGLONG Offset; NTSTATUS Status = STATUS_SUCCESS; + PMM_SECTION_SEGMENT Segment; + LARGE_INTEGER SegmentOffset; + KIRQL OldIrql;
- ExAcquireFastMutex(&RmapListLock); - entry = MmGetRmapListHeadPage(Page); + OldIrql = MiAcquirePfnLock();
-#ifdef NEWCC - // Special case for NEWCC: we can have a page that's only in a segment - // page table - if (entry && RMAP_IS_SEGMENT(entry->Address) && entry->Next == NULL) - { - /* NEWCC does locking itself */ - ExReleaseFastMutex(&RmapListLock); - return MmpPageOutPhysicalAddress(Page); - } -#endif + entry = MmGetRmapListHeadPage(Page);
while (entry && RMAP_IS_SEGMENT(entry->Address)) entry = entry->Next;
if (entry == NULL) { - ExReleaseFastMutex(&RmapListLock); - return(STATUS_UNSUCCESSFUL); + MiReleasePfnLock(OldIrql); + return STATUS_UNSUCCESSFUL; }
Process = entry->Process; - Address = entry->Address;
if ((((ULONG_PTR)Address) & 0xFFF) != 0) @@ -97,12 +85,12 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) { if (!ExAcquireRundownProtection(&Process->RundownProtect)) { - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); return STATUS_PROCESS_IS_TERMINATING; }
Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode); - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); if (!NT_SUCCESS(Status)) { ExReleaseRundownProtection(&Process->RundownProtect); @@ -112,11 +100,12 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) } else { - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); AddressSpace = MmGetKernelAddressSpace(); }
MmLockAddressSpace(AddressSpace); + MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); if (MemoryArea == NULL || MemoryArea->DeleteInProgress) { @@ -128,23 +117,27 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) } return(STATUS_UNSUCCESSFUL); } - Type = MemoryArea->Type; - if (Type == MEMORY_AREA_SECTION_VIEW) + + if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) { ULONG_PTR Entry; - Offset = MemoryArea->SectionData.ViewOffset.QuadPart + + BOOLEAN Dirty; + PFN_NUMBER MapPage; + LARGE_INTEGER Offset; + BOOLEAN Released; + + Offset.QuadPart = MemoryArea->SectionData.ViewOffset.QuadPart + ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea));
- MmLockSectionSegment(MemoryArea->SectionData.Segment); + Segment = MemoryArea->SectionData.Segment;
- /* - * Get or create a pageop - */ - Entry = MmGetPageEntrySectionSegment(MemoryArea->SectionData.Segment, - (PLARGE_INTEGER)&Offset); + MmLockSectionSegment(Segment); + + Entry = MmGetPageEntrySectionSegment(Segment, &Offset); if (Entry && MM_IS_WAIT_PTE(Entry)) { - MmUnlockSectionSegment(MemoryArea->SectionData.Segment); + /* The segment is being read or something. Give up */ + MmUnlockSectionSegment(Segment); MmUnlockAddressSpace(AddressSpace); if (Address < MmSystemRangeStart) { @@ -154,18 +147,101 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) return(STATUS_UNSUCCESSFUL); }
- MmSetPageEntrySectionSegment(MemoryArea->SectionData.Segment, (PLARGE_INTEGER)&Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); + /* Delete this virtual mapping in the process */ + MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage); + ASSERT(MapPage == Page); + + if (Page != PFN_FROM_SSE(Entry)) + { + SWAPENTRY SwapEntry; + + /* This page is private to the process */ + MmUnlockSectionSegment(Segment); + + /* Check if we should write it back to the page file */ + SwapEntry = MmGetSavedSwapEntryPage(Page); + + if ((SwapEntry == 0) && Dirty) + { + /* We don't have a Swap entry, yet the page is dirty. Get one */ + SwapEntry = MmAllocSwapPage(); + if (!SwapEntry) + { + PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), + &MemoryArea->SectionData.RegionListHead, + Address, NULL); + + /* We can't, so let this page in the Process VM */ + MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1); + MmSetDirtyPage(Process, Address); + + MmUnlockAddressSpace(AddressSpace); + return STATUS_UNSUCCESSFUL; + } + } + + if (Dirty) + { + Status = MmWriteToSwapPage(SwapEntry, Page); + if (!NT_SUCCESS(Status)) + { + /* We failed at saving the content of this page. Keep it in */ + PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), + &MemoryArea->SectionData.RegionListHead, + Address, NULL); + + /* This Swap Entry is useless to us */ + MmSetSavedSwapEntryPage(Page, 0); + MmFreeSwapPage(SwapEntry); + + /* We can't, so let this page in the Process VM */ + MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1); + MmSetDirtyPage(Process, Address); + + MmUnlockAddressSpace(AddressSpace); + return STATUS_UNSUCCESSFUL; + } + } + + if (SwapEntry) + { + /* Keep this in the process VM */ + MmCreatePageFileMapping(Process, Address, SwapEntry); + MmSetSavedSwapEntryPage(Page, 0); + } + + MmUnlockAddressSpace(AddressSpace); + + /* We can finally let this page go */ + MmDeleteRmap(Page, Process, Address); + MmReleasePageMemoryConsumer(MC_USER, Page); + + ASSERT(MmGetRmapListHeadPage(Page) == NULL); + + if (Address < MmSystemRangeStart) + { + ExReleaseRundownProtection(&Process->RundownProtect); + ObDereferenceObject(Process); + } + return STATUS_SUCCESS; + } + + /* Delete this RMAP */ + MmDeleteRmap(Page, Process, Address);
- /* - * Release locks now we have a page op. - */ - MmUnlockSectionSegment(MemoryArea->SectionData.Segment); + /* One less mapping referencing this segment */ + Released = MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, FALSE, NULL); + + MmUnlockSectionSegment(Segment); MmUnlockAddressSpace(AddressSpace);
- /* - * Do the actual page out work. - */ - Status = MmPageOutSectionView(AddressSpace, MemoryArea, Address, Entry); + if (Address < MmSystemRangeStart) + { + ExReleaseRundownProtection(&Process->RundownProtect); + ObDereferenceObject(Process); + } + + if (Released) return STATUS_SUCCESS; } #ifdef NEWCC else if (Type == MEMORY_AREA_CACHE) @@ -185,51 +261,52 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page) ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Process); } - return(Status); -} - -VOID -NTAPI -MmSetCleanAllRmaps(PFN_NUMBER Page) -{ - PMM_RMAP_ENTRY current_entry;
- ExAcquireFastMutex(&RmapListLock); - current_entry = MmGetRmapListHeadPage(Page); - if (current_entry == NULL) - { - DPRINT1("MmIsDirtyRmap: No rmaps.\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - while (current_entry != NULL) + /* Now write this page to file, if needed */ + Segment = MmGetSectionAssociation(Page, &SegmentOffset); + if (Segment) { - if (!RMAP_IS_SEGMENT(current_entry->Address)) - MmSetCleanPage(current_entry->Process, current_entry->Address); - current_entry = current_entry->Next; + BOOLEAN Released; + + MmLockSectionSegment(Segment); + + Released = MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE); + + MmUnlockSectionSegment(Segment); + + MmDereferenceSegment(Segment); + + if (Released) + { + return STATUS_SUCCESS; + } } - ExReleaseFastMutex(&RmapListLock); + + /* If we are here, then we didn't release the page */ + return STATUS_UNSUCCESSFUL; }
VOID NTAPI -MmSetDirtyAllRmaps(PFN_NUMBER Page) +MmSetCleanAllRmaps(PFN_NUMBER Page) { PMM_RMAP_ENTRY current_entry; + KIRQL OldIrql;
- ExAcquireFastMutex(&RmapListLock); + OldIrql = MiAcquirePfnLock(); current_entry = MmGetRmapListHeadPage(Page); if (current_entry == NULL) { - DPRINT1("MmIsDirtyRmap: No rmaps.\n"); + DPRINT1("MmSetCleanAllRmaps: No rmaps.\n"); KeBugCheck(MEMORY_MANAGEMENT); } while (current_entry != NULL) { if (!RMAP_IS_SEGMENT(current_entry->Address)) - MmSetDirtyPage(current_entry->Process, current_entry->Address); + MmSetCleanPage(current_entry->Process, current_entry->Address); current_entry = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); }
BOOLEAN @@ -237,27 +314,31 @@ NTAPI MmIsDirtyPageRmap(PFN_NUMBER Page) { PMM_RMAP_ENTRY current_entry; + KIRQL OldIrql; + BOOLEAN Dirty = FALSE;
- ExAcquireFastMutex(&RmapListLock); + OldIrql = MiAcquirePfnLock(); current_entry = MmGetRmapListHeadPage(Page); if (current_entry == NULL) { - ExReleaseFastMutex(&RmapListLock); - return(FALSE); + DPRINT1("MmIsDirtyPageRmap: No rmaps.\n"); + KeBugCheck(MEMORY_MANAGEMENT); } while (current_entry != NULL) { - if ( - !RMAP_IS_SEGMENT(current_entry->Address) && - MmIsDirtyPage(current_entry->Process, current_entry->Address)) + if (!RMAP_IS_SEGMENT(current_entry->Address)) { - ExReleaseFastMutex(&RmapListLock); - return(TRUE); + if (MmIsDirtyPage(current_entry->Process, current_entry->Address)) + { + Dirty = TRUE; + break; + } } current_entry = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); - return(FALSE); + MiReleasePfnLock(OldIrql); + + return Dirty; }
VOID @@ -268,6 +349,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, PMM_RMAP_ENTRY current_entry; PMM_RMAP_ENTRY new_entry; ULONG PrevSize; + KIRQL OldIrql; + if (!RMAP_IS_SEGMENT(Address)) Address = (PVOID)PAGE_ROUND_DOWN(Address);
@@ -298,7 +381,7 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, KeBugCheck(MEMORY_MANAGEMENT); }
- ExAcquireFastMutex(&RmapListLock); + OldIrql = MiAcquirePfnLock(); current_entry = MmGetRmapListHeadPage(Page); new_entry->Next = current_entry; #if DBG @@ -318,7 +401,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, } #endif MmSetRmapListHeadPage(Page, new_entry); - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); + if (!RMAP_IS_SEGMENT(Address)) { if (Process == NULL) @@ -336,63 +420,15 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, } }
-VOID -NTAPI -MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context, - VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process, - PVOID Address)) -{ - PMM_RMAP_ENTRY current_entry; - PMM_RMAP_ENTRY previous_entry; - PEPROCESS Process; - - ExAcquireFastMutex(&RmapListLock); - current_entry = MmGetRmapListHeadPage(Page); - if (current_entry == NULL) - { - DPRINT1("MmDeleteAllRmaps: No rmaps.\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - MmSetRmapListHeadPage(Page, NULL); - ExReleaseFastMutex(&RmapListLock); - - while (current_entry != NULL) - { - previous_entry = current_entry; - current_entry = current_entry->Next; - if (!RMAP_IS_SEGMENT(previous_entry->Address)) - { - if (DeleteMapping) - { - DeleteMapping(Context, previous_entry->Process, - previous_entry->Address); - } - Process = previous_entry->Process; - ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry); - if (Process == NULL) - { - Process = PsInitialSystemProcess; - } - if (Process) - { - (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE); - } - } - else - { - ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry); - } - } -} - VOID NTAPI MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address) { PMM_RMAP_ENTRY current_entry, previous_entry; + KIRQL OldIrql;
- ExAcquireFastMutex(&RmapListLock); + OldIrql = MiAcquirePfnLock(); previous_entry = NULL; current_entry = MmGetRmapListHeadPage(Page);
@@ -409,7 +445,8 @@ MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, { previous_entry->Next = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); + ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry); if (!RMAP_IS_SEGMENT(Address)) { @@ -450,8 +487,8 @@ MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset) { PCACHE_SECTION_PAGE_TABLE Result = NULL; PMM_RMAP_ENTRY current_entry;//, previous_entry; + KIRQL OldIrql = MiAcquirePfnLock();
- ExAcquireFastMutex(&RmapListLock); //previous_entry = NULL; current_entry = MmGetRmapListHeadPage(Page); while (current_entry != NULL) @@ -460,14 +497,20 @@ MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset) { Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process; *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK; - InterlockedIncrementUL(&Result->Segment->ReferenceCount); - ExReleaseFastMutex(&RmapListLock); + if (*Result->Segment->Flags & MM_SEGMENT_INDELETE) + { + MiReleasePfnLock(OldIrql); + return NULL; + } + + InterlockedIncrementUL(Result->Segment->ReferenceCount); + MiReleasePfnLock(OldIrql); return Result; } //previous_entry = current_entry; current_entry = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); return NULL; }
@@ -482,8 +525,8 @@ NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page) { PMM_RMAP_ENTRY current_entry, previous_entry; + KIRQL OldIrql = MiAcquirePfnLock();
- ExAcquireFastMutex(&RmapListLock); previous_entry = NULL; current_entry = MmGetRmapListHeadPage(Page); while (current_entry != NULL) @@ -498,12 +541,12 @@ MmDeleteSectionAssociation(PFN_NUMBER Page) { previous_entry->Next = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry); return; } previous_entry = current_entry; current_entry = current_entry->Next; } - ExReleaseFastMutex(&RmapListLock); + MiReleasePfnLock(OldIrql); } diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index 4d29f5a9ff4..39ae8bf75f5 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -193,6 +193,58 @@ static GENERIC_MAPPING MmpSectionMapping = /* FUNCTIONS *****************************************************************/
+ +NTSTATUS +NTAPI +MiWritePage(PMM_SECTION_SEGMENT Segment, + LONGLONG SegOffset, + PFN_NUMBER Page) +/* + * FUNCTION: write a page for a section backed memory area. + * PARAMETERS: + * MemoryArea - Memory area to write the page for. + * Offset - Offset of the page to write. + * Page - Page which contains the data to write. + */ +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + KEVENT Event; + UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)]; + PMDL Mdl = (PMDL)MdlBase; + PFILE_OBJECT FileObject = Segment->FileObject; + LARGE_INTEGER FileOffset; + PFSRTL_COMMON_FCB_HEADER Fcb = FileObject->FsContext; + + FileOffset.QuadPart = Segment->Image.FileOffset + SegOffset; + + /* Check if we are not writing off-limit */ + if (FileOffset.QuadPart >= Fcb->AllocationSize.QuadPart) + { + return STATUS_SUCCESS; + } + + RtlZeroMemory(MdlBase, sizeof(MdlBase)); + MmInitializeMdl(Mdl, NULL, PAGE_SIZE); + MmBuildMdlFromPages(Mdl, &Page); + Mdl->MdlFlags |= MDL_PAGES_LOCKED; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Status = IoSynchronousPageWrite(FileObject, Mdl, &FileOffset, &Event, &IoStatus); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) + { + MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); + } + + return Status; +} + + /* References: [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object @@ -713,6 +765,8 @@ l_ReadHeaderFromFile:
nStatus = STATUS_INVALID_IMAGE_FORMAT;
+ ASSERT(ImageSectionObject->RefCount > 0); + /* convert the executable sections into segments. See also [1], section 4 */ for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i) { @@ -824,51 +878,146 @@ MmspWaitForFileLock(PFILE_OBJECT File) //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL); }
+ + VOID NTAPI -MmFreeSectionSegments(PFILE_OBJECT FileObject) +MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment) { - if (FileObject->SectionObjectPointer->ImageSectionObject != NULL) + ULONG Length; + LARGE_INTEGER Offset; + ULONG_PTR Entry; + SWAPENTRY SavedSwapEntry; + PFN_NUMBER Page; + + Page = 0; + + MmLockSectionSegment(Segment); + + Length = PAGE_ROUND_UP(Segment->Length.QuadPart); + for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE) { - PMM_IMAGE_SECTION_OBJECT ImageSectionObject; + Entry = MmGetPageEntrySectionSegment(Segment, &Offset); + if (Entry) + { + MmSetPageEntrySectionSegment(Segment, &Offset, 0); + if (IS_SWAP_FROM_SSE(Entry)) + { + MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); + } + else + { + Page = PFN_FROM_SSE(Entry); + SavedSwapEntry = MmGetSavedSwapEntryPage(Page); + if (SavedSwapEntry != 0) + { + MmSetSavedSwapEntryPage(Page, 0); + MmFreeSwapPage(SavedSwapEntry); + } + MmReleasePageMemoryConsumer(MC_USER, Page); + } + } + } + + MmUnlockSectionSegment(Segment); +} + +static +VOID +NTAPI +FreeSegmentPage(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset) +{ + ULONG_PTR Entry; + PFN_NUMBER Page; + + MmLockSectionSegment(Segment); + + Entry = MmGetPageEntrySectionSegment(Segment, Offset); + + MmUnlockSectionSegment(Segment); + + /* This must be either a valid entry or nothing */ + ASSERT(!IS_SWAP_FROM_SSE(Entry)); + + /* There should be no reference anymore */ + ASSERT(SHARE_COUNT_FROM_SSE(Entry) == 0); + + Page = PFN_FROM_SSE(Entry); + /* If there is a page, this must be because it's still dirty */ + ASSERT(Page != 0); + + /* Write the page */ + if (IS_DIRTY_SSE(Entry)) + MiWritePage(Segment, Offset->QuadPart, Page); + + MmReleasePageMemoryConsumer(MC_USER, Page); +} + +VOID +NTAPI +MmDereferenceSegment(PMM_SECTION_SEGMENT Segment) +{ + KIRQL OldIrql; + + /* Lock the PFN lock because we mess around with SectionObjectPointers */ + OldIrql = MiAcquirePfnLock(); + + if (InterlockedDecrementUL(Segment->ReferenceCount) > 0) + { + /* Nothing to do yet */ + MiReleasePfnLock(OldIrql); + return; + } + + *Segment->Flags |= MM_SEGMENT_INDELETE; + + MiReleasePfnLock(OldIrql); + + /* Flush the segment */ + if (*Segment->Flags & MM_DATAFILE_SEGMENT) + { + /* Free the page table. This will flush any remaining dirty data */ + MmFreePageTablesSectionSegment(Segment, FreeSegmentPage); + + OldIrql = MiAcquirePfnLock(); + /* Delete the pointer on the file */ + ASSERT(Segment->FileObject->SectionObjectPointer->DataSectionObject == Segment); + Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL; + MiReleasePfnLock(OldIrql); + ObDereferenceObject(Segment->FileObject); + + ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT); + } + else + { + /* Most grotesque thing ever */ + PMM_IMAGE_SECTION_OBJECT ImageSectionObject = CONTAINING_RECORD(Segment->ReferenceCount, MM_IMAGE_SECTION_OBJECT, RefCount); PMM_SECTION_SEGMENT SectionSegments; ULONG NrSegments; ULONG i;
- ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject; + OldIrql = MiAcquirePfnLock(); + /* Delete the pointer on the file */ + ASSERT(ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject == ImageSectionObject); + ImageSectionObject->FileObject->SectionObjectPointer->ImageSectionObject = NULL; + MiReleasePfnLock(OldIrql); + + ObDereferenceObject(ImageSectionObject->FileObject); + NrSegments = ImageSectionObject->NrSegments; SectionSegments = ImageSectionObject->Segments; for (i = 0; i < NrSegments; i++) { - if (SectionSegments[i].ReferenceCount != 0) + if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) { - DPRINT1("Image segment %lu still referenced (was %lu)\n", i, - SectionSegments[i].ReferenceCount); - KeBugCheck(MEMORY_MANAGEMENT); + MmpFreePageFileSegment(&SectionSegments[i]); } + MmFreePageTablesSectionSegment(&SectionSegments[i], NULL); } - ObDereferenceObject(ImageSectionObject->FileObject); - ExFreePool(ImageSectionObject->Segments); - ExFreePool(ImageSectionObject); - FileObject->SectionObjectPointer->ImageSectionObject = NULL; - } - if (FileObject->SectionObjectPointer->DataSectionObject != NULL) - { - PMM_SECTION_SEGMENT Segment;
- Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> - DataSectionObject; - - if (Segment->ReferenceCount != 0) - { - DPRINT1("Data segment still referenced\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - ObDereferenceObject(Segment->FileObject); - MmFreePageTablesSectionSegment(Segment, NULL); - ExFreePool(Segment); - FileObject->SectionObjectPointer->DataSectionObject = NULL; + ExFreePoolWithTag(ImageSectionObject->Segments, TAG_MM_SECTION_SEGMENT); + ExFreePoolWithTag(ImageSectionObject, TAG_MM_SECTION_SEGMENT); } }
@@ -908,7 +1057,9 @@ MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, ULONG_PTR *InEntry) { ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset); - BOOLEAN IsDirectMapped = FALSE; + PFN_NUMBER Page = PFN_FROM_SSE(Entry); + ULONG_PTR NewEntry = 0; + SWAPENTRY SwapEntry;
if (Entry == 0) { @@ -924,142 +1075,66 @@ MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, { KeBugCheck(MEMORY_MANAGEMENT); } + Dirty = Dirty || IS_DIRTY_SSE(Entry); Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1); - /* - * If we reducing the share count of this entry to zero then set the entry - * to zero and tell the cache the page is no longer mapped. - */ - if (SHARE_COUNT_FROM_SSE(Entry) == 0) - { - PFILE_OBJECT FileObject; - SWAPENTRY SavedSwapEntry; - PFN_NUMBER Page; -#ifndef NEWCC - PROS_SHARED_CACHE_MAP SharedCacheMap; - BOOLEAN IsImageSection; - LARGE_INTEGER FileOffset; + if (Dirty) Entry = DIRTY_SSE(Entry);
- FileOffset.QuadPart = Offset->QuadPart + Segment->Image.FileOffset; - IsImageSection = MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap; -#endif + if (SHARE_COUNT_FROM_SSE(Entry) > 0) + { + /* Update the page mapping in the segment and we're done */ + if (InEntry) + *InEntry = Entry; + else + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + return FALSE; + }
- Page = PFN_FROM_SSE(Entry); - FileObject = Segment->FileObject; - if (FileObject != NULL && - !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { + if (IS_DIRTY_SSE(Entry) && !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) + { + ASSERT(!Segment->WriteCopy); + ASSERT(MmGetSavedSwapEntryPage(Page) == 0);
-#ifndef NEWCC - if ((FileOffset.QuadPart % PAGE_SIZE) == 0 && - (Offset->QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection)) - { - NTSTATUS Status; - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - IsDirectMapped = TRUE; -#ifndef NEWCC - Status = CcRosUnmapVacb(SharedCacheMap, FileOffset.QuadPart, Dirty); -#else - Status = STATUS_SUCCESS; -#endif - if (!NT_SUCCESS(Status)) - { - DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status); - KeBugCheck(MEMORY_MANAGEMENT); - } - } -#endif - } + /* The entry must be written back to the disk, so let this in the segment, the page-out thread will take care of this */ + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + return FALSE; + }
- SavedSwapEntry = MmGetSavedSwapEntryPage(Page); - if (SavedSwapEntry == 0) - { - if (!PageOut && (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { - /* - * FIXME: - * Try to page out this page and set the swap entry - * within the section segment. There exist no rmap entry - * for this page. The pager thread can't page out a - * page without a rmap entry. - */ - MmSetPageEntrySectionSegment(Segment, Offset, Entry); - if (InEntry) *InEntry = Entry; - MiSetPageEvent(NULL, NULL); - } - else - { - MmSetPageEntrySectionSegment(Segment, Offset, 0); - if (InEntry) *InEntry = 0; - MiSetPageEvent(NULL, NULL); - if (!IsDirectMapped) - { - MmReleasePageMemoryConsumer(MC_USER, Page); - } - } - } - else + SwapEntry = MmGetSavedSwapEntryPage(Page); + if (Dirty && !SwapEntry) + { + SwapEntry = MmAllocSwapPage(); + if (!SwapEntry) { - if (Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) - { - if (!PageOut) - { - if (Dirty) - { - /* - * 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; - Status = MmWriteToSwapPage(SavedSwapEntry, Page); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status); - KeBugCheck(MEMORY_MANAGEMENT); - } - } - MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry)); - if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry); - MmSetSavedSwapEntryPage(Page, 0); - MiSetPageEvent(NULL, NULL); - } - MmReleasePageMemoryConsumer(MC_USER, Page); - } - else - { - DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } + /* We can't have a swap entry for this page. Let the segment keep it */ + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + return FALSE; } } - else + + if (Dirty) { - if (InEntry) - *InEntry = Entry; - else + NTSTATUS Status = MmWriteToSwapPage(SwapEntry, Page); + if (!NT_SUCCESS(Status)) + { + /* We failed. Clean up */ + MmSetSavedSwapEntryPage(Page, 0); + MmFreeSwapPage(SwapEntry); MmSetPageEntrySectionSegment(Segment, Offset, Entry); + return FALSE; + } } - return(SHARE_COUNT_FROM_SSE(Entry) > 0); -}
-BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea, - LONGLONG SegOffset) -{ -#ifndef NEWCC - if (!(MemoryArea->SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) + if (SwapEntry) { - PROS_SHARED_CACHE_MAP SharedCacheMap; - PROS_VACB Vacb; - SharedCacheMap = MemoryArea->SectionData.Segment->FileObject->SectionObjectPointer->SharedCacheMap; - Vacb = CcRosLookupVacb(SharedCacheMap, SegOffset + MemoryArea->SectionData.Segment->Image.FileOffset); - if (Vacb) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, FALSE, TRUE); - return TRUE; - } + NewEntry = MAKE_SWAP_SSE(SwapEntry); + MmSetSavedSwapEntryPage(Page, 0); } -#endif - return FALSE; + + /* We can let this go */ + MmSetPageEntrySectionSegment(Segment, Offset, NewEntry); + MmReleasePageMemoryConsumer(MC_USER, Page); + MiSetPageEvent(NULL, NULL); + return TRUE; }
NTSTATUS @@ -1097,175 +1172,46 @@ MiReadPage(PMEMORY_AREA MemoryArea, * Page - Variable that receives a page contains the read data. */ { - LONGLONG BaseOffset; - LONGLONG FileOffset; - PVOID BaseAddress; - BOOLEAN UptoDate; - PROS_VACB Vacb; - PFILE_OBJECT FileObject; NTSTATUS Status; - LONGLONG RawLength; - PROS_SHARED_CACHE_MAP SharedCacheMap; - BOOLEAN IsImageSection; - LONGLONG Length; - - FileObject = MemoryArea->SectionData.Segment->FileObject; - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - RawLength = MemoryArea->SectionData.Segment->RawLength.QuadPart; - FileOffset = SegOffset + MemoryArea->SectionData.Segment->Image.FileOffset; - IsImageSection = MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap; - - ASSERT(SharedCacheMap); + IO_STATUS_BLOCK IoStatus; + KEVENT Event; + UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)]; + PMDL Mdl = (PMDL)MdlBase; + PFILE_OBJECT FileObject = MemoryArea->SectionData.Segment->FileObject; + LARGE_INTEGER FileOffset; + PFSRTL_COMMON_FCB_HEADER Fcb = FileObject->FsContext;
- DPRINT("%S %I64x\n", FileObject->FileName.Buffer, FileOffset); + FileOffset.QuadPart = MemoryArea->SectionData.Segment->Image.FileOffset + SegOffset;
- /* - * If the file system is letting us go directly to the cache and the - * memory area was mapped at an offset in the file which is page aligned - * then get the related VACB. - */ - if (((FileOffset % PAGE_SIZE) == 0) && - ((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) && - !(MemoryArea->SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { + Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, Page); + if (!NT_SUCCESS(Status)) + return Status;
- /* - * Get the related VACB; we use a lower level interface than - * filesystems do because it is safe for us to use an offset with an - * alignment less than the file system block size. - */ - Status = CcRosGetVacb(SharedCacheMap, - FileOffset, - &BaseOffset, - &BaseAddress, - &UptoDate, - &Vacb); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (!UptoDate) - { - /* - * If the VACB isn't up to date then call the file - * system to read in the data. - */ - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - return Status; - } - } + /* Check if we are beyond the file */ + if (FileOffset.QuadPart > Fcb->FileSize.QuadPart) + return STATUS_SUCCESS;
- /* Probe the page, since it's PDE might not be synced */ - (void)*((volatile char*)BaseAddress + FileOffset - BaseOffset); + RtlZeroMemory(MdlBase, sizeof(MdlBase)); + MmInitializeMdl(Mdl, NULL, PAGE_SIZE); + MmBuildMdlFromPages(Mdl, Page); + Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ;
- /* - * Retrieve the page from the view that we actually want. - */ - (*Page) = MmGetPhysicalAddress((char*)BaseAddress + - FileOffset - BaseOffset).LowPart >> PAGE_SHIFT; + KeInitializeEvent(&Event, NotificationEvent, FALSE);
- CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, TRUE); + Status = IoPageRead(FileObject, Mdl, &FileOffset, &Event, &IoStatus); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, WrPageIn, KernelMode, FALSE, NULL); + Status = IoStatus.Status; } - else + if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { - PEPROCESS Process; - KIRQL Irql; - PVOID PageAddr; - LONGLONG VacbOffset; + MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); + }
- /* - * Allocate a page, this is rather complicated by the possibility - * we might have to move other things out of memory - */ - MI_SET_USAGE(MI_USAGE_SECTION); - MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); - Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - Status = CcRosGetVacb(SharedCacheMap, - FileOffset, - &BaseOffset, - &BaseAddress, - &UptoDate, - &Vacb); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (!UptoDate) - { - /* - * If the VACB isn't up to date then call the file - * system to read in the data. - */ - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - return Status; - } - } + return Status; +}
- Process = PsGetCurrentProcess(); - PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql); - VacbOffset = BaseOffset + VACB_MAPPING_GRANULARITY - FileOffset; - Length = RawLength - SegOffset; - if (Length <= VacbOffset && Length <= PAGE_SIZE) - { - memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, Length); - } - else if (VacbOffset >= PAGE_SIZE) - { - memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, PAGE_SIZE); - } - else - { - memcpy(PageAddr, (char*)BaseAddress + FileOffset - BaseOffset, VacbOffset); - MiUnmapPageInHyperSpace(Process, PageAddr, Irql); - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); - Status = CcRosGetVacb(SharedCacheMap, - FileOffset + VacbOffset, - &BaseOffset, - &BaseAddress, - &UptoDate, - &Vacb); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (!UptoDate) - { - /* - * If the VACB isn't up to date then call the file - * system to read in the data. - */ - Status = CcReadVirtualAddress(Vacb); - if (!NT_SUCCESS(Status)) - { - CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); - return Status; - } - } - PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql); - if (Length < PAGE_SIZE) - { - memcpy((char*)PageAddr + VacbOffset, BaseAddress, Length - VacbOffset); - } - else - { - memcpy((char*)PageAddr + VacbOffset, BaseAddress, PAGE_SIZE - VacbOffset); - } - } - MiUnmapPageInHyperSpace(Process, PageAddr, Irql); - CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); - } - return(STATUS_SUCCESS); -} #else NTSTATUS NTAPI @@ -1571,7 +1517,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, /* * Add the page to the process's working set */ - MmInsertRmap(Page, Process, Address); + if (Process) MmInsertRmap(Page, Process, Address); /* * Finish the operation */ @@ -1684,7 +1630,8 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, KeBugCheck(MEMORY_MANAGEMENT); } ASSERT(MmIsPagePresent(Process, PAddress)); - MmInsertRmap(Page, Process, Address); + if (Process) + MmInsertRmap(Page, Process, Address);
/* Set this section offset has being backed by our new page. */ Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); @@ -1765,7 +1712,8 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, DPRINT1("Unable to create virtual mapping\n"); KeBugCheck(MEMORY_MANAGEMENT); } - MmInsertRmap(Page, Process, Address); + if (Process) + MmInsertRmap(Page, Process, Address);
/* * Mark the offset within the section as having valid, in-memory @@ -1794,7 +1742,9 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace, DPRINT1("Unable to create virtual mapping\n"); KeBugCheck(MEMORY_MANAGEMENT); } - MmInsertRmap(Page, Process, Address); + + if (Process) + MmInsertRmap(Page, Process, Address);
/* Take a reference on it */ MmSharePageEntrySectionSegment(Segment, &Offset); @@ -1878,609 +1828,58 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace, PFN_FROM_SSE(Entry) != OldPage) { MmUnlockSectionSegment(Segment); - /* This is a private page. We must only change the page protection. */ - MmSetPageProtect(Process, PAddress, Region->Protect); - return(STATUS_SUCCESS); - } - - /* - * Allocate a page - */ - MI_SET_USAGE(MI_USAGE_SECTION); - if (Process) MI_SET_PROCESS2(Process->ImageFileName); - if (!Process) MI_SET_PROCESS2("Kernel Section"); - Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(MEMORY_MANAGEMENT); - } - - /* - * Copy the old page - */ - NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress))); - - /* - * Unshare the old page. - */ - DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage); - MmDeleteVirtualMapping(Process, PAddress, NULL, NULL); - MmDeleteRmap(OldPage, Process, PAddress); - MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, FALSE, FALSE, NULL); - MmUnlockSectionSegment(Segment); - - /* - * Set the PTE to point to the new page - */ - Status = MmCreateVirtualMapping(Process, - PAddress, - Region->Protect, - &NewPage, - 1); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n"); - KeBugCheck(MEMORY_MANAGEMENT); - return(Status); - } - MmInsertRmap(NewPage, Process, PAddress); - - MiSetPageEvent(Process, Address); - DPRINT("Address 0x%p\n", Address); - return(STATUS_SUCCESS); -} - -VOID -MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address) -{ - MM_SECTION_PAGEOUT_CONTEXT* PageOutContext; - BOOLEAN WasDirty; - PFN_NUMBER Page = 0; - - PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context; - if (Process) - { - MmLockAddressSpace(&Process->Vm); - } - - MmDeleteVirtualMapping(Process, - Address, - &WasDirty, - &Page); - if (WasDirty) - { - PageOutContext->WasDirty = TRUE; - } - if (!PageOutContext->Private) - { - MmLockSectionSegment(PageOutContext->Segment); - MmUnsharePageEntrySectionSegment(PageOutContext->MemoryArea, - PageOutContext->Segment, - &PageOutContext->Offset, - PageOutContext->WasDirty, - TRUE, - &PageOutContext->SectionEntry); - MmUnlockSectionSegment(PageOutContext->Segment); - } - if (Process) - { - MmUnlockAddressSpace(&Process->Vm); - } - - if (PageOutContext->Private) - { - MmReleasePageMemoryConsumer(MC_USER, Page); - } -} - -NTSTATUS -NTAPI -MmPageOutSectionView(PMMSUPPORT AddressSpace, - MEMORY_AREA* MemoryArea, - PVOID Address, ULONG_PTR Entry) -{ - PFN_NUMBER Page; - MM_SECTION_PAGEOUT_CONTEXT Context; - SWAPENTRY SwapEntry; - NTSTATUS Status; -#ifndef NEWCC - ULONGLONG FileOffset; - PFILE_OBJECT FileObject; - PROS_SHARED_CACHE_MAP SharedCacheMap = NULL; - BOOLEAN IsImageSection; -#endif - BOOLEAN DirectMapped; - PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); - KIRQL OldIrql; - - Address = (PVOID)PAGE_ROUND_DOWN(Address); - - /* - * Get the segment and section. - */ - Context.Segment = MemoryArea->SectionData.Segment; - Context.MemoryArea = MemoryArea; - Context.SectionEntry = Entry; - Context.CallingProcess = Process; - - Context.Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) - + MemoryArea->SectionData.ViewOffset.QuadPart; - - DirectMapped = FALSE; - - MmLockSectionSegment(Context.Segment); - -#ifndef NEWCC - FileOffset = Context.Offset.QuadPart + Context.Segment->Image.FileOffset; - IsImageSection = MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap; - FileObject = Context.Segment->FileObject; - - if (FileObject != NULL && - !(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - - /* - * If the file system is letting us go directly to the cache and the - * memory area was mapped at an offset in the file which is page aligned - * then note this is a direct mapped page. - */ - if ((FileOffset % PAGE_SIZE) == 0 && - (Context.Offset.QuadPart + PAGE_SIZE <= Context.Segment->RawLength.QuadPart || !IsImageSection)) - { - DirectMapped = TRUE; - } - } -#endif - - /* - * Get the section segment entry and the physical address. - */ - if (!MmIsPagePresent(Process, Address)) - { - DPRINT1("Trying to page out not-present page at (%p,0x%p).\n", - Process ? Process->UniqueProcessId : 0, Address); - KeBugCheck(MEMORY_MANAGEMENT); - } - Page = MmGetPfnForProcess(Process, Address); - SwapEntry = MmGetSavedSwapEntryPage(Page); - - /* - * Check the reference count to ensure this page can be paged out - */ - if (MmGetReferenceCountPage(Page) != 1) - { - DPRINT("Cannot page out locked section page: 0x%lu (RefCount: %lu)\n", - Page, MmGetReferenceCountPage(Page)); - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); - MmUnlockSectionSegment(Context.Segment); - return STATUS_UNSUCCESSFUL; - } - - /* - * Prepare the context structure for the rmap delete call. - */ - MmUnlockSectionSegment(Context.Segment); - Context.WasDirty = FALSE; - if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page) - { - Context.Private = TRUE; - } - else - { - Context.Private = FALSE; - } - - /* - * Take an additional reference to the page or the VACB. - */ - if (DirectMapped && !Context.Private) - { - if(!MiIsPageFromCache(MemoryArea, Context.Offset.QuadPart)) - { - DPRINT1("Direct mapped non private page is not associated with the cache.\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - } - else - { - OldIrql = MiAcquirePfnLock(); - MmReferencePage(Page); - MiReleasePfnLock(OldIrql); - } - - MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping); - - /* Since we passed in a surrogate, we'll get back the page entry - * state in our context. This is intended to make intermediate - * decrements of share count not release the wait entry. - */ - Entry = Context.SectionEntry; - - /* - * If this wasn't a private page then we should have reduced the entry to - * zero by deleting all the rmaps. - */ - if (!Context.Private && Entry != 0) - { - if (!(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { - KeBugCheckEx(MEMORY_MANAGEMENT, Entry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); - } - } - - /* - * If the page wasn't dirty then we can just free it as for a readonly page. - * Since we unmapped all the mappings above we know it will not suddenly - * become dirty. - * If the page is from a pagefile section and has no swap entry, - * we can't free the page at this point. - */ - SwapEntry = MmGetSavedSwapEntryPage(Page); - if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) - { - if (Context.Private) - { - DPRINT1("Found a %s private page (address %p) in a shared section segment.\n", - Context.WasDirty ? "dirty" : "clean", Address); - KeBugCheckEx(MEMORY_MANAGEMENT, Page, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); - } - if (!Context.WasDirty || SwapEntry != 0) - { - MmSetSavedSwapEntryPage(Page, 0); - if (SwapEntry != 0) - { - MmLockSectionSegment(Context.Segment); - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry)); - MmUnlockSectionSegment(Context.Segment); - } - MmReleasePageMemoryConsumer(MC_USER, Page); - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); - } - } - else if (!Context.Private && DirectMapped) - { - if (SwapEntry != 0) - { - DPRINT1("Found a swapentry for a non private and direct mapped page (address %p)\n", - Address); - KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address); - } -#ifndef NEWCC - Status = CcRosUnmapVacb(SharedCacheMap, FileOffset, FALSE); -#else - Status = STATUS_SUCCESS; -#endif -#ifndef NEWCC - if (!NT_SUCCESS(Status)) - { - DPRINT1("CcRosUnmapVacb failed, status = %x\n", Status); - KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)SharedCacheMap, (ULONG_PTR)FileOffset, (ULONG_PTR)Address); - } -#endif - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); - } - else if (!Context.WasDirty && !DirectMapped && !Context.Private) - { - if (SwapEntry != 0) - { - DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %p)\n", - Address); - KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address); - } - MmReleasePageMemoryConsumer(MC_USER, Page); - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); - } - else if (!Context.WasDirty && Context.Private && SwapEntry != 0) - { - DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address); - MmSetSavedSwapEntryPage(Page, 0); - MmLockAddressSpace(AddressSpace); - Status = MmCreatePageFileMapping(Process, - Address, - SwapEntry); - MmUnlockAddressSpace(AddressSpace); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Status %x Swapping out %p:%p\n", Status, Process, Address); - KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry); - } - MmReleasePageMemoryConsumer(MC_USER, Page); - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); - } - - /* - * If necessary, allocate an entry in the paging file for this page - */ - if (SwapEntry == 0) - { - SwapEntry = MmAllocSwapPage(); - if (SwapEntry == 0) - { - MmShowOutOfSpaceMessagePagingFile(); - MmLockAddressSpace(AddressSpace); - /* - * For private pages restore the old mappings. - */ - if (Context.Private) - { - Status = MmCreateVirtualMapping(Process, - Address, - MmProtectToValue[MemoryArea->VadNode.u.VadFlags.Protection], - &Page, - 1); - MmSetDirtyPage(Process, Address); - MmInsertRmap(Page, - Process, - Address); - } - 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 - * our copy. Otherwise it will be handled by the cache manager. - */ - Status = MmCreateVirtualMapping(Process, - Address, - MmProtectToValue[MemoryArea->VadNode.u.VadFlags.Protection], - &Page, - 1); - MmSetDirtyPage(Process, Address); - MmInsertRmap(Page, - Process, - Address); - // If we got here, the previous entry should have been a wait - Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); - OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset); - ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY)); - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); - MmUnlockSectionSegment(Context.Segment); - } - MmUnlockAddressSpace(AddressSpace); - MiSetPageEvent(NULL, NULL); - return(STATUS_PAGEFILE_QUOTA); - } - } - - /* - * Write the page to the pagefile - */ - Status = MmWriteToSwapPage(SwapEntry, Page); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", - Status); - /* - * As above: undo our actions. - * FIXME: Also free the swap page. - */ - MmLockAddressSpace(AddressSpace); - if (Context.Private) - { - Status = MmCreateVirtualMapping(Process, - Address, - MmProtectToValue[MemoryArea->VadNode.u.VadFlags.Protection], - &Page, - 1); - MmSetDirtyPage(Process, Address); - MmInsertRmap(Page, - Process, - Address); - } - else - { - MmLockSectionSegment(Context.Segment); - Status = MmCreateVirtualMapping(Process, - Address, - MmProtectToValue[MemoryArea->VadNode.u.VadFlags.Protection], - &Page, - 1); - MmSetDirtyPage(Process, Address); - MmInsertRmap(Page, - Process, - Address); - Entry = MAKE_SSE(Page << PAGE_SHIFT, 1); - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); - MmUnlockSectionSegment(Context.Segment); - } - MmUnlockAddressSpace(AddressSpace); - MiSetPageEvent(NULL, NULL); - return(STATUS_UNSUCCESSFUL); - } - - /* - * Otherwise we have succeeded. - */ - DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT); - MmSetSavedSwapEntryPage(Page, 0); - if (Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) - { - MmLockSectionSegment(Context.Segment); - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry)); - MmUnlockSectionSegment(Context.Segment); - } - else - { - MmReleasePageMemoryConsumer(MC_USER, Page); - } - - if (Context.Private) - { - MmLockAddressSpace(AddressSpace); - MmLockSectionSegment(Context.Segment); - Status = MmCreatePageFileMapping(Process, - Address, - SwapEntry); - /* We had placed a wait entry upon entry ... replace it before leaving */ - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); - MmUnlockSectionSegment(Context.Segment); - MmUnlockAddressSpace(AddressSpace); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Status %x Creating page file mapping for %p:%p\n", Status, Process, Address); - KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry); - } - } - else - { - MmLockAddressSpace(AddressSpace); - MmLockSectionSegment(Context.Segment); - Entry = MAKE_SWAP_SSE(SwapEntry); - /* We had placed a wait entry upon entry ... replace it before leaving */ - MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry); - MmUnlockSectionSegment(Context.Segment); - MmUnlockAddressSpace(AddressSpace); - } - - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); -} - -NTSTATUS -NTAPI -MmWritePageSectionView(PMMSUPPORT AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID Address, - ULONG PageEntry) -{ - LARGE_INTEGER Offset; - PMM_SECTION_SEGMENT Segment; - PFN_NUMBER Page; - SWAPENTRY SwapEntry; - ULONG_PTR Entry; - BOOLEAN Private; - NTSTATUS Status; - PFILE_OBJECT FileObject; -#ifndef NEWCC - PROS_SHARED_CACHE_MAP SharedCacheMap = NULL; -#endif - BOOLEAN DirectMapped; - BOOLEAN IsImageSection; - PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); - - Address = (PVOID)PAGE_ROUND_DOWN(Address); - - Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea) - + MemoryArea->SectionData.ViewOffset.QuadPart; - - /* - * Get the segment and section. - */ - Segment = MemoryArea->SectionData.Segment; - IsImageSection = MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap; - - FileObject = Segment->FileObject; - DirectMapped = FALSE; - if (FileObject != NULL && - !(Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)) - { -#ifndef NEWCC - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; -#endif - - /* - * If the file system is letting us go directly to the cache and the - * memory area was mapped at an offset in the file which is page aligned - * then note this is a direct mapped page. - */ - if (((Offset.QuadPart + Segment->Image.FileOffset) % PAGE_SIZE) == 0 && - (Offset.QuadPart + PAGE_SIZE <= Segment->RawLength.QuadPart || !IsImageSection)) - { - DirectMapped = TRUE; - } - } - - /* - * Get the section segment entry and the physical address. - */ - Entry = MmGetPageEntrySectionSegment(Segment, &Offset); - if (!MmIsPagePresent(Process, Address)) - { - DPRINT1("Trying to page out not-present page at (%p,0x%p).\n", - Process ? Process->UniqueProcessId : 0, Address); - KeBugCheck(MEMORY_MANAGEMENT); + /* This is a private page. We must only change the page protection. */ + MmSetPageProtect(Process, PAddress, Region->Protect); + return(STATUS_SUCCESS); } - Page = MmGetPfnForProcess(Process, Address); - SwapEntry = MmGetSavedSwapEntryPage(Page);
/* - * Check for a private (COWed) page. + * Allocate a page */ - if (IS_SWAP_FROM_SSE(Entry) || PFN_FROM_SSE(Entry) != Page) - { - Private = TRUE; - } - else + MI_SET_USAGE(MI_USAGE_SECTION); + if (Process) MI_SET_PROCESS2(Process->ImageFileName); + if (!Process) MI_SET_PROCESS2("Kernel Section"); + Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); + if (!NT_SUCCESS(Status)) { - Private = FALSE; + KeBugCheck(MEMORY_MANAGEMENT); }
/* - * Speculatively set all mappings of the page to clean. - */ - MmSetCleanAllRmaps(Page); - - /* - * If this page was direct mapped from the cache then the cache manager - * will take care of writing it back to disk. + * Copy the old page */ - if (DirectMapped && !Private) - { - //LARGE_INTEGER SOffset; - ASSERT(SwapEntry == 0); - //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset; -#ifndef NEWCC - CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart); -#endif - MmLockSectionSegment(Segment); - MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry); - MmUnlockSectionSegment(Segment); - MiSetPageEvent(NULL, NULL); - return(STATUS_SUCCESS); - } + NT_VERIFY(NT_SUCCESS(MiCopyFromUserPage(NewPage, PAddress)));
/* - * If necessary, allocate an entry in the paging file for this page + * Unshare the old page. */ - if (SwapEntry == 0) - { - SwapEntry = MmAllocSwapPage(); - if (SwapEntry == 0) - { - MmSetDirtyAllRmaps(Page); - MiSetPageEvent(NULL, NULL); - return(STATUS_PAGEFILE_QUOTA); - } - MmSetSavedSwapEntryPage(Page, SwapEntry); - } + DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage); + MmDeleteVirtualMapping(Process, PAddress, NULL, NULL); + if (Process) + MmDeleteRmap(OldPage, Process, PAddress); + MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, FALSE, FALSE, NULL); + MmUnlockSectionSegment(Segment);
/* - * Write the page to the pagefile + * Set the PTE to point to the new page */ - Status = MmWriteToSwapPage(SwapEntry, Page); + Status = MmCreateVirtualMapping(Process, + PAddress, + Region->Protect, + &NewPage, + 1); if (!NT_SUCCESS(Status)) { - DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", - Status); - MmSetDirtyAllRmaps(Page); - MiSetPageEvent(NULL, NULL); - return(STATUS_UNSUCCESSFUL); + DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n"); + KeBugCheck(MEMORY_MANAGEMENT); + return(Status); }
- /* - * Otherwise we have succeeded. - */ - DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT); - MiSetPageEvent(NULL, NULL); + if (Process) + MmInsertRmap(NewPage, Process, PAddress); + + MiSetPageEvent(Process, Address); + DPRINT("Address 0x%p\n", Address); return(STATUS_SUCCESS); }
@@ -2560,48 +1959,6 @@ MmQuerySectionView(PMEMORY_AREA MemoryArea, return(STATUS_SUCCESS); }
-VOID -NTAPI -MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment) -{ - ULONG Length; - LARGE_INTEGER Offset; - ULONG_PTR Entry; - SWAPENTRY SavedSwapEntry; - PFN_NUMBER Page; - - Page = 0; - - MmLockSectionSegment(Segment); - - Length = PAGE_ROUND_UP(Segment->Length.QuadPart); - for (Offset.QuadPart = 0; Offset.QuadPart < Length; Offset.QuadPart += PAGE_SIZE) - { - Entry = MmGetPageEntrySectionSegment(Segment, &Offset); - if (Entry) - { - MmSetPageEntrySectionSegment(Segment, &Offset, 0); - if (IS_SWAP_FROM_SSE(Entry)) - { - MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); - } - else - { - Page = PFN_FROM_SSE(Entry); - SavedSwapEntry = MmGetSavedSwapEntryPage(Page); - if (SavedSwapEntry != 0) - { - MmSetSavedSwapEntryPage(Page, 0); - MmFreeSwapPage(SavedSwapEntry); - } - MmReleasePageMemoryConsumer(MC_USER, Page); - } - } - } - - MmUnlockSectionSegment(Segment); -} - VOID NTAPI MmpDeleteSection(PVOID ObjectBody) { @@ -2617,10 +1974,7 @@ MmpDeleteSection(PVOID ObjectBody) DPRINT("MmpDeleteSection(ObjectBody %p)\n", ObjectBody); if (Section->u.Flags.Image) { - ULONG i; - ULONG NrSegments; - ULONG RefCount; - PMM_SECTION_SEGMENT SectionSegments; + PMM_IMAGE_SECTION_OBJECT ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)Section->Segment;
/* * NOTE: Section->ImageSection can be NULL for short time @@ -2631,25 +1985,9 @@ MmpDeleteSection(PVOID ObjectBody) if (Section->Segment == NULL) return;
- SectionSegments = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment)->Segments; - NrSegments = ((PMM_IMAGE_SECTION_OBJECT)Section->Segment)->NrSegments; - - for (i = 0; i < NrSegments; i++) - { - if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) - { - MmLockSectionSegment(&SectionSegments[i]); - } - RefCount = InterlockedDecrementUL(&SectionSegments[i].ReferenceCount); - if (SectionSegments[i].Image.Characteristics & IMAGE_SCN_MEM_SHARED) - { - MmUnlockSectionSegment(&SectionSegments[i]); - if (RefCount == 0) - { - MmpFreePageFileSegment(&SectionSegments[i]); - } - } - } + /* We just dereference the first segment */ + ASSERT(ImageSectionObject->RefCount > 0); + MmDereferenceSegment(ImageSectionObject->Segments); } #ifdef NEWCC else if (Section->Segment && Section->Segment->Flags & MM_DATAFILE_SEGMENT) @@ -2672,25 +2010,17 @@ MmpDeleteSection(PVOID ObjectBody) #endif else { + PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; + /* * NOTE: Section->Segment can be NULL for short time * during the section creating. */ - if (Section->Segment == NULL) + if (Segment == NULL) return;
- (void)InterlockedDecrementUL(&((PMM_SECTION_SEGMENT)Section->Segment)->ReferenceCount); - } - - if (Section->Segment) - { - PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; - if (Segment->FileObject != NULL) - { - #ifndef NEWCC - CcRosDereferenceCache(Segment->FileObject); - #endif - } + Segment->SectionCount--; + MmDereferenceSegment(Segment); } }
@@ -2763,13 +2093,17 @@ MmCreatePhysicalMemorySection(VOID) } RtlZeroMemory(Segment, sizeof(MM_SECTION_SEGMENT)); PhysSection->Segment = (PSEGMENT)Segment; - Segment->ReferenceCount = 1; + Segment->RefCount = 1; + + Segment->ReferenceCount = &Segment->RefCount; + Segment->Flags = &Segment->SegFlags; + ExInitializeFastMutex(&Segment->Lock); Segment->Image.FileOffset = 0; Segment->Protection = PAGE_EXECUTE_READWRITE; Segment->RawLength = SectionSize; Segment->Length = SectionSize; - Segment->Flags = 0; + Segment->SegFlags = 0; Segment->WriteCopy = FALSE; Segment->Image.VirtualAddress = 0; Segment->Image.Characteristics = 0; @@ -2823,6 +2157,7 @@ MmInitSectionImplementation(VOID) return(STATUS_SUCCESS); }
+static NTSTATUS NTAPI MmCreateDataFileSection(PSECTION *SectionObject, @@ -2831,7 +2166,8 @@ MmCreateDataFileSection(PSECTION *SectionObject, PLARGE_INTEGER UMaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, - PFILE_OBJECT FileObject) + PFILE_OBJECT FileObject, + BOOLEAN GotFileHandle) /* * Create a section backed by a data file */ @@ -2840,8 +2176,7 @@ MmCreateDataFileSection(PSECTION *SectionObject, NTSTATUS Status; LARGE_INTEGER MaximumSize; PMM_SECTION_SEGMENT Segment; - FILE_STANDARD_INFORMATION FileInfo; - ULONG Length; + KIRQL OldIrql;
/* * Create the section @@ -2869,63 +2204,63 @@ MmCreateDataFileSection(PSECTION *SectionObject, Section->u.Flags.filler = 1; Section->InitialPageProtection = SectionPageProtection; Section->u.Flags.File = 1; + if (AllocationAttributes & SEC_NO_CHANGE) Section->u.Flags.NoChange = 1;
- /* - * FIXME: This is propably not entirely correct. We can't look into - * the standard FCB header because it might not be initialized yet - * (as in case of the EXT2FS driver by Manoj Paul Joseph where the - * standard file information is filled on first request). - */ - Status = IoQueryFileInformation(FileObject, - FileStandardInformation, - sizeof(FILE_STANDARD_INFORMATION), - &FileInfo, - &Length); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - return Status; - } - - /* - * FIXME: Revise this once a locking order for file size changes is - * decided - */ - if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0)) + if (!GotFileHandle) { + ASSERT(UMaximumSize != NULL); + ASSERT(UMaximumSize->QuadPart != 0); MaximumSize = *UMaximumSize; } else { - MaximumSize = FileInfo.EndOfFile; - /* Mapping zero-sized files isn't allowed. */ - if (MaximumSize.QuadPart == 0) + LARGE_INTEGER FileSize; + Status = FsRtlGetFileSize(FileObject, &FileSize); + if (!NT_SUCCESS(Status)) { ObDereferenceObject(Section); ObDereferenceObject(FileObject); - return STATUS_MAPPED_FILE_SIZE_ZERO; + return Status; } - }
- if (MaximumSize.QuadPart > FileInfo.EndOfFile.QuadPart) - { - Status = IoSetInformation(FileObject, - FileEndOfFileInformation, - sizeof(LARGE_INTEGER), - &MaximumSize); - if (!NT_SUCCESS(Status)) + /* + * FIXME: Revise this once a locking order for file size changes is + * decided + */ + if ((UMaximumSize != NULL) && (UMaximumSize->QuadPart != 0)) { - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - return(STATUS_SECTION_NOT_EXTENDED); + MaximumSize = *UMaximumSize; + } + else + { + MaximumSize = FileSize; + /* Mapping zero-sized files isn't allowed. */ + if (MaximumSize.QuadPart == 0) + { + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + return STATUS_MAPPED_FILE_SIZE_ZERO; + } + } + + if (MaximumSize.QuadPart > FileSize.QuadPart) + { + Status = IoSetInformation(FileObject, + FileEndOfFileInformation, + sizeof(LARGE_INTEGER), + &MaximumSize); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + return(STATUS_SECTION_NOT_EXTENDED); + } } }
- if (FileObject->SectionObjectPointer == NULL || - FileObject->SectionObjectPointer->SharedCacheMap == NULL) + if (FileObject->SectionObjectPointer == NULL) { ObDereferenceObject(Section); ObDereferenceObject(FileObject); @@ -2943,34 +2278,61 @@ MmCreateDataFileSection(PSECTION *SectionObject, return(Status); }
+ /* Lock the PFN lock while messing with Section Object pointers */ + OldIrql = MiAcquirePfnLock(); + Segment = FileObject->SectionObjectPointer->DataSectionObject; + + while (Segment && (Segment->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE))) + { + LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}}; + + MiReleasePfnLock(OldIrql); + KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); + OldIrql = MiAcquirePfnLock(); + Segment = FileObject->SectionObjectPointer->DataSectionObject; + } + /* * If this file hasn't been mapped as a data file before then allocate a * section segment to describe the data file mapping */ - if (FileObject->SectionObjectPointer->DataSectionObject == NULL) + if (Segment == NULL) { Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), TAG_MM_SECTION_SEGMENT); if (Segment == NULL) { //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); + MiReleasePfnLock(OldIrql); ObDereferenceObject(Section); ObDereferenceObject(FileObject); return(STATUS_NO_MEMORY); } + + /* We are creating it */ + RtlZeroMemory(Segment, sizeof(*Segment)); + Segment->SegFlags = MM_DATAFILE_SEGMENT | MM_SEGMENT_INCREATE; + Segment->RefCount = 1; + + FileObject->SectionObjectPointer->DataSectionObject = Segment; + + /* We're safe to release the lock now */ + MiReleasePfnLock(OldIrql); + Section->Segment = (PSEGMENT)Segment; - Segment->ReferenceCount = 1; + + /* Self-referencing segment */ + Segment->Flags = &Segment->SegFlags; + Segment->ReferenceCount = &Segment->RefCount; + + Segment->SectionCount = 1; + ExInitializeFastMutex(&Segment->Lock); Segment->FileObject = FileObject; - /* - * Set the lock before assigning the segment to the file object - */ - ExAcquireFastMutex(&Segment->Lock); - FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
Segment->Image.FileOffset = 0; Segment->Protection = SectionPageProtection; - Segment->Flags = MM_DATAFILE_SEGMENT; + Segment->Image.Characteristics = 0; Segment->WriteCopy = (SectionPageProtection & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)); if (AllocationAttributes & SEC_RESERVE) @@ -2983,20 +2345,21 @@ MmCreateDataFileSection(PSECTION *SectionObject, Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); } Segment->Image.VirtualAddress = 0; - Segment->Locked = TRUE; MiInitializeSectionPageTable(Segment); + + /* We're good to use it now */ + OldIrql = MiAcquirePfnLock(); + Segment->SegFlags &= ~MM_SEGMENT_INCREATE; + MiReleasePfnLock(OldIrql); } else { - /* - * If the file is already mapped as a data file then we may need - * to extend it - */ - Segment = - (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> - DataSectionObject; Section->Segment = (PSEGMENT)Segment; - (void)InterlockedIncrementUL(&Segment->ReferenceCount); + Segment->RefCount++; + InterlockedIncrementUL(&Segment->SectionCount); + + MiReleasePfnLock(OldIrql); + MmLockSectionSegment(Segment);
if (MaximumSize.QuadPart > Segment->RawLength.QuadPart && @@ -3006,15 +2369,13 @@ MmCreateDataFileSection(PSECTION *SectionObject, Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart); }
- /* We let the segment reference the file object */ + MmUnlockSectionSegment(Segment); + + /* The segment already has a reference to a file object. Don't bother keeping one.*/ ObDereferenceObject(FileObject); - FileObject = Segment->FileObject; } - MmUnlockSectionSegment(Segment); Section->SizeOfSection = MaximumSize; -#ifndef NEWCC - CcRosReferenceCache(FileObject); -#endif + //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); *SectionObject = Section; return(STATUS_SUCCESS); @@ -3541,7 +2902,6 @@ ExeFmtpCreateImageSection(PFILE_OBJECT FileObject, */ for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i) { - RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); Flags = 0;
Status = ExeFmtpLoaders[i](FileHeader, @@ -3580,6 +2940,7 @@ ExeFmtpCreateImageSection(PFILE_OBJECT FileObject, return Status;
ASSERT(ImageSectionObject->Segments != NULL); + ASSERT(ImageSectionObject->RefCount > 0);
/* * Some defaults @@ -3640,11 +3001,14 @@ ExeFmtpCreateImageSection(PFILE_OBJECT FileObject, for ( i = 0; i < ImageSectionObject->NrSegments; ++ i ) { ExInitializeFastMutex(&ImageSectionObject->Segments[i].Lock); - ImageSectionObject->Segments[i].ReferenceCount = 1; + ImageSectionObject->Segments[i].ReferenceCount = &ImageSectionObject->RefCount; + ImageSectionObject->Segments[i].Flags = &ImageSectionObject->SegFlags; MiInitializeSectionPageTable(&ImageSectionObject->Segments[i]); ImageSectionObject->Segments[i].FileObject = FileObject; }
+ ASSERT(ImageSectionObject->RefCount > 0); + ImageSectionObject->FileObject = FileObject;
ASSERT(NT_SUCCESS(Status)); @@ -3662,20 +3026,18 @@ MmCreateImageSection(PSECTION *SectionObject, { PSECTION Section; NTSTATUS Status; - PMM_SECTION_SEGMENT SectionSegments; PMM_IMAGE_SECTION_OBJECT ImageSectionObject; - ULONG i; + KIRQL OldIrql; +
if (FileObject == NULL) return STATUS_INVALID_FILE_FOR_SECTION;
-#ifndef NEWCC - if (!CcIsFileCached(FileObject)) + if (FileObject->SectionObjectPointer == NULL) { DPRINT1("Denying section creation due to missing cache initialization\n"); return STATUS_INVALID_FILE_FOR_SECTION; } -#endif
/* * Create the section @@ -3709,13 +3071,31 @@ MmCreateImageSection(PSECTION *SectionObject, if (AllocationAttributes & SEC_NO_CHANGE) Section->u.Flags.NoChange = 1;
- if (FileObject->SectionObjectPointer->ImageSectionObject == NULL) + OldIrql = MiAcquirePfnLock(); + + /* Wait for it to be properly created or deleted */ + ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; + while(ImageSectionObject && (ImageSectionObject->SegFlags & (MM_SEGMENT_INDELETE | MM_SEGMENT_INCREATE))) + { + LARGE_INTEGER ShortTime; + + MiReleasePfnLock(OldIrql); + + ShortTime.QuadPart = - 10 * 100 * 1000; + KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); + + OldIrql = MiAcquirePfnLock(); + ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; + } + + if (ImageSectionObject == NULL) { NTSTATUS StatusExeFmt;
- ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); + ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); if (ImageSectionObject == NULL) { + MiReleasePfnLock(OldIrql); ObDereferenceObject(FileObject); ObDereferenceObject(Section); return(STATUS_NO_MEMORY); @@ -3723,10 +3103,21 @@ MmCreateImageSection(PSECTION *SectionObject,
RtlZeroMemory(ImageSectionObject, sizeof(MM_IMAGE_SECTION_OBJECT));
+ ImageSectionObject->SegFlags = MM_SEGMENT_INCREATE; + ImageSectionObject->RefCount = 1; + FileObject->SectionObjectPointer->ImageSectionObject = ImageSectionObject; + + MiReleasePfnLock(OldIrql); + StatusExeFmt = ExeFmtpCreateImageSection(FileObject, ImageSectionObject);
if (!NT_SUCCESS(StatusExeFmt)) { + /* Unset */ + OldIrql = MiAcquirePfnLock(); + FileObject->SectionObjectPointer->ImageSectionObject = NULL; + MiReleasePfnLock(OldIrql); + if(ImageSectionObject->Segments != NULL) ExFreePool(ImageSectionObject->Segments);
@@ -3747,6 +3138,7 @@ MmCreateImageSection(PSECTION *SectionObject,
Section->Segment = (PSEGMENT)ImageSectionObject; ASSERT(ImageSectionObject->Segments); + ASSERT(ImageSectionObject->RefCount > 0);
/* * Lock the file @@ -3754,6 +3146,11 @@ MmCreateImageSection(PSECTION *SectionObject, Status = MmspWaitForFileLock(FileObject); if (!NT_SUCCESS(Status)) { + /* Unset */ + OldIrql = MiAcquirePfnLock(); + FileObject->SectionObjectPointer->ImageSectionObject = NULL; + MiReleasePfnLock(OldIrql); + ExFreePool(ImageSectionObject->Segments); ExFreePool(ImageSectionObject); ObDereferenceObject(Section); @@ -3761,66 +3158,30 @@ MmCreateImageSection(PSECTION *SectionObject, return(Status); }
- if (NULL != InterlockedCompareExchangePointer(&FileObject->SectionObjectPointer->ImageSectionObject, - ImageSectionObject, NULL)) - { - /* - * An other thread has initialized the same image in the background - */ - ExFreePool(ImageSectionObject->Segments); - ExFreePool(ImageSectionObject); - ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; - Section->Segment = (PSEGMENT)ImageSectionObject; - SectionSegments = ImageSectionObject->Segments; - - for (i = 0; i < ImageSectionObject->NrSegments; i++) - { - (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount); - } - - /* We let the Image Section Object hold the reference */ - ObDereferenceObject(FileObject); - FileObject = ImageSectionObject->FileObject; - } + OldIrql = MiAcquirePfnLock(); + ImageSectionObject->SegFlags &= ~MM_SEGMENT_INCREATE; + MiReleasePfnLock(OldIrql);
Status = StatusExeFmt; } else { - /* - * Lock the file - */ - Status = MmspWaitForFileLock(FileObject); - if (Status != STATUS_SUCCESS) - { - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - return(Status); - } + /* Take one ref */ + ImageSectionObject->RefCount++;
- ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; - Section->Segment = (PSEGMENT)ImageSectionObject; - SectionSegments = ImageSectionObject->Segments; + MiReleasePfnLock(OldIrql);
- /* - * Otherwise just reference all the section segments - */ - for (i = 0; i < ImageSectionObject->NrSegments; i++) - { - (void)InterlockedIncrementUL(&SectionSegments[i].ReferenceCount); - } + Section->Segment = (PSEGMENT)ImageSectionObject;
/* We let the Image Section Object hold the reference */ ObDereferenceObject(FileObject); - FileObject = ImageSectionObject->FileObject;
Status = STATUS_SUCCESS; } -#ifndef NEWCC - CcRosReferenceCache(FileObject); -#endif //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); *SectionObject = Section; + ASSERT(ImageSectionObject->RefCount > 0); + return(Status); }
@@ -3908,10 +3269,6 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) { ULONG_PTR Entry; -#ifndef NEWCC - PFILE_OBJECT FileObject; - PROS_SHARED_CACHE_MAP SharedCacheMap; -#endif LARGE_INTEGER Offset; SWAPENTRY SavedSwapEntry; PMM_SECTION_SEGMENT Segment; @@ -3942,18 +3299,12 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, }
/* - * For a dirty, datafile, non-private page mark it as dirty in the - * cache manager. + * For a dirty, datafile, non-private page, there shoulkd be no swap entry */ - if (Segment->Flags & MM_DATAFILE_SEGMENT) + if (*Segment->Flags & MM_DATAFILE_SEGMENT) { if (Page == PFN_FROM_SSE(Entry) && Dirty) { -#ifndef NEWCC - FileObject = MemoryArea->SectionData.Segment->FileObject; - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset); -#endif ASSERT(SwapEntry == 0); } } @@ -3970,6 +3321,8 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, if (IS_SWAP_FROM_SSE(Entry) || Page != PFN_FROM_SSE(Entry)) { + ASSERT(Process != NULL); + /* * Just dereference private pages */ @@ -3984,7 +3337,8 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, } else { - MmDeleteRmap(Page, Process, Address); + if (Process) + MmDeleteRmap(Page, Process, Address); MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, FALSE, NULL); } } @@ -4467,6 +3821,8 @@ MmMapViewOfSection(IN PVOID SectionObject, SectionSegments = ImageSectionObject->Segments; NrSegments = ImageSectionObject->NrSegments;
+ ASSERT(ImageSectionObject->RefCount > 0); + ImageBase = (ULONG_PTR)*BaseAddress; if (ImageBase == 0) { @@ -4550,6 +3906,8 @@ MmMapViewOfSection(IN PVOID SectionObject, PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment; LONGLONG ViewOffset;
+ ASSERT(Segment->RefCount > 0); + /* check for write access */ if ((Protect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) && !(Section->InitialPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))) @@ -4633,68 +3991,58 @@ BOOLEAN NTAPI MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize) { + KIRQL OldIrql = MiAcquirePfnLock(); + BOOLEAN Ret; + PMM_SECTION_SEGMENT Segment; + +CheckSectionPointer: /* Check whether an ImageSectionObject exists */ if (SectionObjectPointer->ImageSectionObject != NULL) { DPRINT1("ERROR: File can't be truncated because it has an image section\n"); + MiReleasePfnLock(OldIrql); + return FALSE; }
- if (SectionObjectPointer->DataSectionObject != NULL) + Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer->DataSectionObject; + /* Wait for it to be created/deleted properly */ + while (Segment && (Segment->SegFlags & (MM_SEGMENT_INCREATE | MM_SEGMENT_INDELETE))) { - PMM_SECTION_SEGMENT Segment; + LARGE_INTEGER ShortTime; + + ShortTime.QuadPart = -10 * 100 * 1000;
- Segment = (PMM_SECTION_SEGMENT)SectionObjectPointer-> - DataSectionObject; + /* Bad luck. Wait a bit for the operation to finish */ + MiReleasePfnLock(OldIrql); + KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); + OldIrql = MiAcquirePfnLock(); + goto CheckSectionPointer; + }
- if (Segment->ReferenceCount != 0) + if (Segment) + { + if ((Segment->SectionCount == 1) && (SectionObjectPointer->SharedCacheMap != NULL)) { -#ifdef NEWCC - CC_FILE_SIZES FileSizes; - CcpLock(); - if (SectionObjectPointer->SharedCacheMap && (Segment->ReferenceCount > CcpCountCacheSections((PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap))) - { - CcpUnlock(); - /* Check size of file */ - if (SectionObjectPointer->SharedCacheMap) - { - if (!CcGetFileSizes(Segment->FileObject, &FileSizes)) - { - return FALSE; - } - - if (NewFileSize->QuadPart <= FileSizes.FileSize.QuadPart) - { - return FALSE; - } - } - } - else - CcpUnlock(); -#else - /* Check size of file */ - if (SectionObjectPointer->SharedCacheMap) - { - PROS_SHARED_CACHE_MAP SharedCacheMap = SectionObjectPointer->SharedCacheMap; - if (NewFileSize->QuadPart <= SharedCacheMap->FileSize.QuadPart) - { - return FALSE; - } - } -#endif + /* If the cache is the only one holding a reference to the segment, then it's fine to resize */ + Ret = TRUE; } else { - /* Something must gone wrong - * how can we have a Section but no - * reference? */ - DPRINT("ERROR: DataSectionObject without reference!\n"); + /* We can't shrink, but we can extend */ + Ret = NewFileSize->QuadPart > Segment->RawLength.QuadPart; } } + else + { + Ret = TRUE; + } + + MiReleasePfnLock(OldIrql);
DPRINT("FIXME: didn't check for outstanding write probes\n");
- return TRUE; + return Ret; }
@@ -4797,8 +4145,7 @@ MmMapViewInSystemSpaceEx (
MmLockAddressSpace(AddressSpace);
- - if ((*ViewSize == 0) || ((SectionOffset->QuadPart + *ViewSize) > Section->SizeOfSection.QuadPart)) + if (*ViewSize == 0) { *ViewSize = MIN((Section->SizeOfSection.QuadPart - SectionOffset->QuadPart), SIZE_T_MAX); } @@ -4812,7 +4159,7 @@ MmMapViewInSystemSpaceEx ( *ViewSize, PAGE_READWRITE, SectionOffset->QuadPart, - 0); + SEC_RESERVE);
MmUnlockSectionSegment(Segment); MmUnlockAddressSpace(AddressSpace); @@ -4946,13 +4293,8 @@ MmCreateSection (OUT PVOID * Section, return STATUS_INVALID_PARAMETER_6; }
- /* Did the caller pass an object? */ - if (FileObject) - { - /* Reference the object directly */ - ObReferenceObject(FileObject); - } - else + /* Did the caller pass a handle? */ + if (FileHandle) { /* Reference the file handle to get the object */ Status = ObReferenceObjectByHandle(FileHandle, @@ -4967,6 +4309,11 @@ MmCreateSection (OUT PVOID * Section, return Status; } } + else + { + /* Reference the object directly */ + ObReferenceObject(FileObject); + } } else { @@ -4974,63 +4321,6 @@ MmCreateSection (OUT PVOID * Section, if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; }
-#ifndef NEWCC // A hack for initializing caching. - // This is needed only in the old case. - if (FileHandle) - { - IO_STATUS_BLOCK Iosb; - NTSTATUS Status; - CHAR Buffer; - LARGE_INTEGER ByteOffset; - ByteOffset.QuadPart = 0; - Status = ZwReadFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - &Buffer, - sizeof(Buffer), - &ByteOffset, - NULL); - if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) - { - DPRINT1("CC failure: %lx\n", Status); - if (FileObject) - ObDereferenceObject(FileObject); - return Status; - } - // Caching is initialized... - - // Hack of the hack: actually, it might not be initialized if FSD init on effective right and if file is null-size - // In such case, force cache by initiating a write IRP - if (Status == STATUS_END_OF_FILE && !(AllocationAttributes & SEC_IMAGE) && FileObject != NULL && - (FileObject->SectionObjectPointer == NULL || FileObject->SectionObjectPointer->SharedCacheMap == NULL)) - { - Buffer = 0xdb; - Status = ZwWriteFile(FileHandle, - NULL, - NULL, - NULL, ... 433 lines suppressed ...