* Herve Poussineau
*/
+/*
+
+A note on this code:
+
+Unlike the previous section code, this code does not rely on an active map
+for a page to exist in a data segment. Each mapping contains a large integer
+offset to map at, and the segment always represents the entire section space
+from zero to the maximum long long. This allows us to associate one single
+page map with each file object, and to let each mapping view an offset into
+the overall mapped file. Temporarily unmapping the file has no effect on the
+section membership.
+
+This necessitates a change in the section page table implementation, which is
+now an RtlGenericTable. This will be elaborated more in sptab.c. One upshot
+of this change is that a mapping of a small files takes a bit more than 1/4
+of the size in nonpaged kernel space as it did previously.
+
+When we need other threads that may be competing for the same page fault to
+wait, we have a mechanism seperate from PageOps for dealing with that, which
+was suggested by Travis Geiselbrecht after a conversation I had with Alex
+Ionescu. That mechanism is the MM_WAIT_ENTRY, which is the all-ones SWAPENTRY.
+
+When we wish for other threads to know that we're waiting and will finish
+handling a page fault, we place the swap entry MM_WAIT_ENTRY in the page table
+at the fault address (this works on either the section page table or a process
+address space), perform any blocking operations required, then replace the
+entry.
+
+*/
+
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
/* GLOBALS *******************************************************************/
-ULONG_PTR MmSubsectionBase;
-
static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
{
ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
while (FileOffset.QuadPart < End.QuadPart)
{
PVOID Address;
- ULONG Entry;
+ ULONG_PTR Entry;
if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
break;
return STATUS_SUCCESS;
}
+/*
+
+MiFlushMappedSection
+
+Called from cache code to cause dirty pages of a section
+to be written back. This doesn't affect the mapping.
+
+BaseOffset is the base at which to start writing in file space.
+FileSize is the length of the file as understood by the cache.
+
+ */
NTSTATUS
NTAPI
_MiFlushMappedSection(PVOID BaseAddress,
PageAddress < EndingAddress;
PageAddress += PAGE_SIZE)
{
- ULONG Entry;
+ ULONG_PTR Entry;
FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
Entry = MmGetPageEntrySectionSegment(MemoryArea->Data.SectionData.Segment,
&FileOffset);
PageAddress < EndingAddress;
PageAddress += PAGE_SIZE)
{
- ULONG Entry;
+ ULONG_PTR Entry;
FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
Entry = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
Page = PFN_FROM_SSE(Entry);
return Status;
}
+/*
+
+This deletes a segment entirely including its page map.
+It must have been unmapped in every address space.
+
+ */
+
VOID
NTAPI
MmFinalizeSegment(PMM_SECTION_SEGMENT Segment)
ULONG AllocationAttributes,
PFILE_OBJECT FileObject)
/*
- * Create a section backed by a data file
+ * Create a section backed by a data file.
*/
{
PROS_SECTION_OBJECT Section;
NTSTATUS Status;
- ULARGE_INTEGER MaximumSize;
+ LARGE_INTEGER MaximumSize;
PMM_SECTION_SEGMENT Segment;
IO_STATUS_BLOCK Iosb;
CC_FILE_SIZES FileSizes;
*/
if (!CcGetFileSizes(FileObject, &FileSizes))
{
+ ULONG Information;
/*
* FIXME: This is propably not entirely correct. We can't look into
* the standard FCB header because it might not be initialized yet
FileStandardInformation,
sizeof(FILE_STANDARD_INFORMATION),
&FileInfo,
- &Iosb.Information);
+ &Information);
+ Iosb.Information = Information;
DPRINT("Query => %x\n", Status);
if (!NT_SUCCESS(Status))
{
KeReleaseSpinLock(&FileObject->IrpListLock, OldIrql);
DPRINTC("Free Segment %x\n", Segment);
- ExFreePool(Segment);
+ ExFreePoolWithTag(Segment, TAG_MM_SECTION_SEGMENT);
DPRINT("Filling out Segment info (previous data section)\n");
return STATUS_SUCCESS;
}
+/*
+
+Completely remove the page at FileOffset in Segment. The page must not
+be mapped.
+
+*/
+
VOID
NTAPI
MiFreeSegmentPage(PMM_SECTION_SEGMENT Segment,
PLARGE_INTEGER FileOffset)
{
- ULONG Entry;
+ ULONG_PTR Entry;
PFILE_OBJECT FileObject = Segment->FileObject;
Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);
SWAPENTRY SwapEntry,
BOOLEAN Dirty)
{
- ULONG Entry;
+ ULONG_PTR Entry;
PVOID *ContextData = Context;
PMMSUPPORT AddressSpace;
PEPROCESS Process;
MmLockSectionSegment(Segment);
Segment->RawLength.QuadPart = NewSize->QuadPart;
Segment->Length.QuadPart = MAX(Segment->Length.QuadPart,
- PAGE_ROUND_UP(Segment->RawLength.LowPart));
+ (LONG64)PAGE_ROUND_UP(Segment->RawLength.QuadPart));
MmUnlockSectionSegment(Segment);
return STATUS_SUCCESS;
}