#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,
RetryMasterLocked = 255,
} CC_CAN_WRITE_RETRY;
-ULONG CcRosTraceLevel = 0;
+ULONG CcRosTraceLevel = CC_API_DEBUG;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadNotPossible;
ULONG CcFastReadNotPossible;
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)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
PROS_VACB Vacb;
ULONG PartialLength;
- PVOID BaseAddress;
- BOOLEAN Valid;
ULONG Length;
PPRIVATE_CACHE_MAP PrivateCacheMap;
BOOLEAN Locked;
{
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))
{
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);
PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
Status = CcRosRequestVacb(SharedCacheMap,
CurrentOffset,
- &BaseAddress,
- &Valid,
&Vacb);
if (!NT_SUCCESS(Status))
{
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);
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);
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;
}
/*
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);
"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;
}
/*
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);
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));
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;
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;
#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;
}
current->SharedCacheMap->LazyWriteContext, Wait);
if (!Locked)
{
+ DPRINT("Not locked!");
+ ASSERT(!Wait);
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
CcRosVacbDecRefCount(current);
continue;
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;
+ }
}
}
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 (
{
KIRQL oldIrql;
PROS_SHARED_CACHE_MAP SharedCacheMap;
+ ULONG Length = VACB_MAPPING_GRANULARITY;
SharedCacheMap = Vacb->SharedCacheMap;
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 */
CcScheduleLazyWriteScan(FALSE);
}
KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
+
+ /* Tell Mm */
+ MmMakePagesDirty(NULL, Vacb->BaseAddress, Length);
}
VOID
{
KIRQL oldIrql;
PROS_SHARED_CACHE_MAP SharedCacheMap;
+ ULONG Length = VACB_MAPPING_GRANULARITY;
SharedCacheMap = Vacb->SharedCacheMap;
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)
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 (
KIRQL oldIrql;
ULONG Refs;
BOOLEAN Retried;
+ SIZE_T ViewSize = VACB_MAPPING_GRANULARITY;
ASSERT(SharedCacheMap);
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;
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;
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);
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);
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)
* 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)
}
#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)
{
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)
{
KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);
KeReleaseQueuedSpinLock(LockQueueMasterLock, *OldIrql);
+ if(SharedCacheMap->Section)
+ ObDereferenceObject(SharedCacheMap->Section);
ObDereferenceObject(SharedCacheMap->FileObject);
while (!IsListEmpty(&FreeList))
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 (
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);
}
}
}
DPRINT("CcRosInitializeFileCache(FileObject 0x%p)\n", FileObject);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
+
Allocated = FALSE;
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
if (SharedCacheMap == NULL)
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;
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;
}
TAG_VACB,
20);
- MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
-
CcInitCacheZeroPage();
}
/* 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
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)
{
//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);
}
}
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)
{
{
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
* 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
/*
* Add the page to the process's working set
*/
- MmInsertRmap(Page, Process, Address);
+ if (Process) MmInsertRmap(Page, Process, Address);
/*
* Finish the operation
*/
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);
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
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);
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);
}
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)
{
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
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)
#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);
}
}
}
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;
return(STATUS_SUCCESS);
}
+static
NTSTATUS
NTAPI
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
*/
NTSTATUS Status;
LARGE_INTEGER MaximumSize;
PMM_SECTION_SEGMENT Segment;
- FILE_STANDARD_INFORMATION FileInfo;
- ULONG Length;
+ KIRQL OldIrql;
/*
* Create the section
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);
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)
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 &&
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);
*/
for (i = 0; i < RTL_NUMBER_OF(ExeFmtpLoaders); ++ i)
{
- RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject));
Flags = 0;
Status = ExeFmtpLoaders[i](FileHeader,
return Status;
ASSERT(ImageSectionObject->Segments != NULL);
+ ASSERT(ImageSectionObject->RefCount > 0);
/*
* Some defaults
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));
{
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
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);
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);
Section->Segment = (PSEGMENT)ImageSectionObject;
ASSERT(ImageSectionObject->Segments);
+ ASSERT(ImageSectionObject->RefCount > 0);
/*
* Lock the file
Status = MmspWaitForFileLock(FileObject);
if (!NT_SUCCESS(Status))
{
+ /* Unset */
+ OldIrql = MiAcquirePfnLock();
+ FileObject->SectionObjectPointer->ImageSectionObject = NULL;
+ MiReleasePfnLock(OldIrql);
+
ExFreePool(ImageSectionObject->Segments);
ExFreePool(ImageSectionObject);
ObDereferenceObject(Section);
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);
}
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;
}
/*
- * 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);
}
}
if (IS_SWAP_FROM_SSE(Entry) ||
Page != PFN_FROM_SSE(Entry))
{
+ ASSERT(Process != NULL);
+
/*
* Just dereference private pages
*/
}
else
{
- MmDeleteRmap(Page, Process, Address);
+ if (Process)
+ MmDeleteRmap(Page, Process, Address);
MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, FALSE, NULL);
}
}
SectionSegments = ImageSectionObject->Segments;
NrSegments = ImageSectionObject->NrSegments;
+ ASSERT(ImageSectionObject->RefCount > 0);
+
ImageBase = (ULONG_PTR)*BaseAddress;
if (ImageBase == 0)
{
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)))
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;
}
MmLockAddressSpace(AddressSpace);
-
- if ((*ViewSize == 0) || ((SectionOffset->QuadPart + *ViewSize) > Section->SizeOfSection.QuadPart))
+ if (*ViewSize == 0)
{
*ViewSize = MIN((Section->SizeOfSection.QuadPart - SectionOffset->QuadPart), SIZE_T_MAX);
}
*ViewSize,
PAGE_READWRITE,
SectionOffset->QuadPart,
- 0);
+ SEC_RESERVE);
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
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,
return Status;
}
}
+ else
+ {
+ /* Reference the object directly */
+ ObReferenceObject(FileObject);
+ }
}
else
{
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,
- &Iosb,
- &Buffer,
- sizeof(Buffer),
- &ByteOffset,
- NULL);
- if (NT_SUCCESS(Status))
- {
- LARGE_INTEGER Zero;
- Zero.QuadPart = 0LL;
-
- Status = IoSetInformation(FileObject,
- FileEndOfFileInformation,
- sizeof(LARGE_INTEGER),
- &Zero);
- ASSERT(NT_SUCCESS(Status));
- }
- }
- }
-#endif
-
if (AllocationAttributes & SEC_IMAGE)
{
Status = MmCreateImageSection(SectionObject,
FileObject);
}
#ifndef NEWCC
- else if (FileHandle != NULL)
+ else if (FileObject != NULL)
{
Status = MmCreateDataFileSection(SectionObject,
DesiredAccess,
MaximumSize,
SectionPageProtection,
AllocationAttributes,
- FileObject);
+ FileObject,
+ FileHandle != NULL);
}
#else
else if (FileHandle != NULL || FileObject != NULL)
#endif
else
{
- /* All cases should be handled above, and the Physical Memorw section was created at initialization phase */
+ /* All cases should be handled above */
ASSERT(FALSE);
Status = STATUS_INVALID_PARAMETER;
if (FileObject)
BOOLEAN Ret = TRUE;
PMM_SECTION_SEGMENT Segment;
LARGE_INTEGER SegmentOffset, RangeEnd;
+ PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
- MmLockAddressSpace(&Process->Vm);
+ MmLockAddressSpace(AddressSpace);
- MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, Address);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
if (MemoryArea == NULL)
{
- MmUnlockAddressSpace(&Process->Vm);
+ MmUnlockAddressSpace(AddressSpace);
return FALSE;
}
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(&Process->Vm);
+ MmUnlockAddressSpace(AddressSpace);
return Ret;
}
PMEMORY_AREA MemoryArea;
PMM_SECTION_SEGMENT Segment;
LARGE_INTEGER SegmentOffset, RangeEnd;
+ PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
- MmLockAddressSpace(&Process->Vm);
+ MmLockAddressSpace(AddressSpace);
- MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, Address);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
if (MemoryArea == NULL)
{
- MmUnlockAddressSpace(&Process->Vm);
- return FALSE;
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_NOT_MAPPED_VIEW;
}
/* Only supported in old Mm for now */
RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->SectionData.ViewOffset.QuadPart;
+ DPRINT("MmMakePagesResident: Segment %p, 0x%I64x -> 0x%I64x\n", Segment, SegmentOffset.QuadPart, RangeEnd.QuadPart);
+
while (SegmentOffset.QuadPart < RangeEnd.QuadPart)
{
ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
while (MM_IS_WAIT_PTE(Entry))
{
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(&Process->Vm);
+ MmUnlockAddressSpace(AddressSpace);
MiWaitForPageEvent(NULL, NULL);
- MmLockAddressSpace(&Process->Vm);
+ MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
}
*/
MmSetPageEntrySectionSegment(Segment, &SegmentOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(&Process->Vm);
+ MmUnlockAddressSpace(AddressSpace);
/* FIXME: Read the whole range at once instead of one page at a time */
Status = MiReadPage(MemoryArea, SegmentOffset.QuadPart, &Page);
return Status;
}
- MmLockAddressSpace(&Process->Vm);
+ MmLockAddressSpace(AddressSpace);
+ MmLockSectionSegment(Segment);
+
+ /* We set it with 0 ref count, nobody maps this page yet. */
+ MmSetPageEntrySectionSegment(Segment, &SegmentOffset, MAKE_SSE(Page << PAGE_SHIFT, 0));
+ MiSetPageEvent(Process, Address);
+ }
+ SegmentOffset.QuadPart += PAGE_SIZE;
+ }
+
+ MmUnlockSectionSegment(Segment);
+
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmRosFlushVirtualMemory(
+ _In_ PEPROCESS Process,
+ _Inout_ PVOID* Address,
+ _Inout_ PSIZE_T Length,
+ _Out_ PIO_STATUS_BLOCK Iosb)
+{
+ PMEMORY_AREA MemoryArea;
+ PMM_SECTION_SEGMENT Segment;
+ LARGE_INTEGER SegmentOffset, RangeEnd;
+ PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
+ PVOID CurrentAddress;
+
+ PAGED_CODE();
+
+ MmLockAddressSpace(AddressSpace);
+
+ DPRINT("Flushing Process %p at %p --> 0x%x", Process, *Address, *Length);
+
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *Address);
+ if ((MemoryArea == NULL) || (MemoryArea->Type != MEMORY_AREA_SECTION_VIEW) ||
+ (MemoryArea->VadNode.u.VadFlags.VadType == VadImageMap))
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_NOT_MAPPED_VIEW;
+ }
+
+ Segment = MemoryArea->SectionData.Segment;
+
+ SegmentOffset.QuadPart = PAGE_ROUND_DOWN(*Address) - MA_GetStartingAddress(MemoryArea)
+ + MemoryArea->SectionData.ViewOffset.QuadPart;
+ RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)*Address + *Length) - MA_GetStartingAddress(MemoryArea)
+ + MemoryArea->SectionData.ViewOffset.QuadPart;
+
+ CurrentAddress = *Address;
+
+ MmUnlockAddressSpace(AddressSpace);
+
+ MmLockSectionSegment(Segment);
+
+ Iosb->Information = 0;
+ while (SegmentOffset.QuadPart < RangeEnd.QuadPart)
+ {
+ ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
+
+ /* Let any pending read proceed */
+ while (MM_IS_WAIT_PTE(Entry))
+ {
+ MmUnlockSectionSegment(Segment);
+ MiWaitForPageEvent(NULL, NULL);
+ MmLockSectionSegment(Segment);
+ Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
+ }
+
+ /* We are called from Cc, this can't be backed by the page files */
+ ASSERT(!IS_SWAP_FROM_SSE(Entry));
+
+ /* At this point, there may be a valid page there */
+ if (Entry != 0)
+ {
+ /* This will write the page to disk, if needed */
+ MmCheckDirtySegment(Segment, &SegmentOffset, MmIsDirtyPage(Process, CurrentAddress), FALSE);
+ Iosb->Information += PAGE_SIZE;
+ }
+ SegmentOffset.QuadPart += PAGE_SIZE;
+ CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + PAGE_SIZE);
+ }
+
+ MmUnlockSectionSegment(Segment);
+
+ return STATUS_SUCCESS;
+}
+
+_Requires_exclusive_lock_held_(Segment->Lock)
+BOOLEAN
+NTAPI
+MmCheckDirtySegment(
+ PMM_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset,
+ BOOLEAN ForceDirty,
+ BOOLEAN PageOut)
+{
+ ULONG_PTR Entry;
+ NTSTATUS Status;
+ PFN_NUMBER Page;
+
+ ASSERT(Segment->Locked);
+
+ DPRINT("Checking segment for file %wZ at offset 0x%I64X.\n", &Segment->FileObject->FileName, Offset->QuadPart);
+
+ Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+ if (Entry == 0)
+ return FALSE;
+
+ Page = PFN_FROM_SSE(Entry);
+ if ((IS_DIRTY_SSE(Entry)) || ForceDirty)
+ {
+ BOOLEAN DirtyAgain;
+
+ /* We got a dirty entry. Is this segment copy on write */
+ ASSERT(!Segment->WriteCopy);
+ ASSERT(Segment->SegFlags & MM_DATAFILE_SEGMENT);
+
+ /* Insert the cleaned entry back. Keep one ref to the page so nobody pages it out again behind us */
+ MmSetPageEntrySectionSegment(Segment, Offset,
+ MAKE_SSE(Page << PAGE_SHIFT, SHARE_COUNT_FROM_SSE(Entry) + 1));
+
+ /* Tell the other users that we are clean again */
+ MmSetCleanAllRmaps(Page);
+
+ MmUnlockSectionSegment(Segment);
+
+ /* Go ahead and write the page */
+ Status = MiWritePage(Segment, Offset->QuadPart, Page);
+
+ MmLockSectionSegment(Segment);
+
+ /* Get the entry again */
+ Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+ ASSERT(PFN_FROM_SSE(Entry) == Page);
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* Damn, this failed. Consider this page as still dirty */
+ DPRINT1("MiWritePage FAILED: Status 0x%08x!\n", Status);
+ DirtyAgain = TRUE;
+ }
+ else
+ {
+ /* Check if someone dirtified this page while we were not looking */
+ DirtyAgain = IS_DIRTY_SSE(Entry) || MmIsDirtyPageRmap(Page);
+ }
+
+ /* Drop the reference we got */
+ Entry = MAKE_SSE(Page << PAGE_SHIFT, SHARE_COUNT_FROM_SSE(Entry) - 1);
+ if (DirtyAgain) Entry = DIRTY_SSE(Entry);
+ MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+ }
+
+ /* Were this page hanging there just for the sake of being present ? */
+ if (!IS_DIRTY_SSE(Entry) && (SHARE_COUNT_FROM_SSE(Entry) == 0) && PageOut)
+ {
+ /* Yes. Release it */
+ MmSetPageEntrySectionSegment(Segment, Offset, 0);
+ MmReleasePageMemoryConsumer(MC_USER, Page);
+ /* Tell the caller we released the page */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+NTSTATUS
+NTAPI
+MmMakePagesDirty(
+ _In_ PEPROCESS Process,
+ _In_ PVOID Address,
+ _In_ ULONG Length)
+{
+ PMEMORY_AREA MemoryArea;
+ PMM_SECTION_SEGMENT Segment;
+ LARGE_INTEGER SegmentOffset, RangeEnd;
+ PMMSUPPORT AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
+
+ MmLockAddressSpace(AddressSpace);
+
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ if (MemoryArea == NULL)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_NOT_MAPPED_VIEW;
+ }
+
+ /* Only supported in old Mm for now */
+ ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
+ /* For file mappings */
+ ASSERT(MemoryArea->VadNode.u.VadFlags.VadType != VadImageMap);
+
+ Segment = MemoryArea->SectionData.Segment;
+ MmLockSectionSegment(Segment);
+
+ SegmentOffset.QuadPart = PAGE_ROUND_DOWN(Address) - MA_GetStartingAddress(MemoryArea)
+ + MemoryArea->SectionData.ViewOffset.QuadPart;
+ RangeEnd.QuadPart = PAGE_ROUND_UP((ULONG_PTR)Address + Length) - MA_GetStartingAddress(MemoryArea)
+ + MemoryArea->SectionData.ViewOffset.QuadPart;
+
+ DPRINT("MmMakePagesResident: Segment %p, 0x%I64x -> 0x%I64x\n", Segment, SegmentOffset.QuadPart, RangeEnd.QuadPart);
+
+ while (SegmentOffset.QuadPart < RangeEnd.QuadPart)
+ {
+ ULONG_PTR Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
+
+ /* Let any pending read proceed */
+ while (MM_IS_WAIT_PTE(Entry))
+ {
+ MmUnlockSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ MiWaitForPageEvent(NULL, NULL);
+ MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
- MmSetPageEntrySectionSegment(Segment, &SegmentOffset, MAKE_SSE(Page << PAGE_SHIFT, 1));
+ Entry = MmGetPageEntrySectionSegment(Segment, &SegmentOffset);
+ }
+
+ /* We are called from Cc, this can't be backed by the page files */
+ ASSERT(!IS_SWAP_FROM_SSE(Entry));
+
+ /* If there is no page there, there is nothing to make dirty */
+ if (Entry != 0)
+ {
+ /* Dirtify the entry */
+ MmSetPageEntrySectionSegment(Segment, &SegmentOffset, DIRTY_SSE(Entry));
}
+
SegmentOffset.QuadPart += PAGE_SIZE;
}
MmUnlockSectionSegment(Segment);
- MmUnlockAddressSpace(&Process->Vm);
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmExtendSection(
+ _In_ PVOID _Section,
+ _Inout_ PLARGE_INTEGER NewSize)
+{
+ PSECTION Section = _Section;
+
+ /* It makes no sense to extend an image mapping */
+ if (Section->u.Flags.Image)
+ return STATUS_SECTION_NOT_EXTENDED;
+
+ /* Nor is it possible to extend a page file mapping */
+ if (!Section->u.Flags.File)
+ return STATUS_SECTION_NOT_EXTENDED;
+
+ if (!MiIsRosSectionObject(Section))
+ return STATUS_NOT_IMPLEMENTED;
+
+ /* We just extend the sizes. Shrinking is a no-op ? */
+ if (NewSize->QuadPart > Section->SizeOfSection.QuadPart)
+ {
+ PMM_SECTION_SEGMENT Segment = (PMM_SECTION_SEGMENT)Section->Segment;
+ Section->SizeOfSection = *NewSize;
+
+ MmLockSectionSegment(Segment);
+ if (Segment->RawLength.QuadPart < NewSize->QuadPart)
+ {
+ Segment->RawLength = *NewSize;
+ Segment->Length.QuadPart = (NewSize->QuadPart + PAGE_SIZE - 1) & ~((LONGLONG)PAGE_SIZE);
+ }
+ MmUnlockSectionSegment(Segment);
+ }
+
return STATUS_SUCCESS;
}