-/* $Id: pagefile.c,v 1.3 2000/03/26 19:38:32 ea Exp $
+/*
+ * ReactOS kernel
+ * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
*
- * COPYRIGHT: See COPYING in the top level directory
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/pagefile.c
* PURPOSE: Paging file functions
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/bitops.h>
-#include <internal/io.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
#include <internal/debug.h>
-/* TYPES *********************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmInitPagingFile)
+#endif
-typedef ULONG SWAPENTRY;
-typedef struct _PPAGINGFILE
+/* TYPES *********************************************************************/
+
+typedef struct _PAGINGFILE
{
LIST_ENTRY PagingFileListEntry;
PFILE_OBJECT FileObject;
- ULONG MaximumSize;
- ULONG CurrentSize;
+ LARGE_INTEGER MaximumSize;
+ LARGE_INTEGER CurrentSize;
ULONG FreePages;
ULONG UsedPages;
PULONG AllocMap;
KSPIN_LOCK AllocMapLock;
ULONG AllocMapSize;
-} PAGINGFILE, *PPAGINGFILE;
+ PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+}
+PAGINGFILE, *PPAGINGFILE;
+
+typedef struct _RETRIEVEL_DESCRIPTOR_LIST
+{
+ struct _RETRIEVEL_DESCRIPTOR_LIST* Next;
+ RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+}
+RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
/* GLOBALS *******************************************************************/
+#define PAIRS_PER_RUN (1024)
+
#define MAX_PAGING_FILES (32)
+/* List of paging files, both used and free */
static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
+
+/* Lock for examining the list of paging files */
static KSPIN_LOCK PagingFileListLock;
-static ULONG MiFreeSwapPages;
-static ULONG MiUsedSwapPages;
+/* Number of paging files */
+static ULONG MiPagingFileCount;
+
+/* Number of pages that are available for swapping */
+ULONG MiFreeSwapPages;
+
+/* Number of pages that have been allocated for swapping */
+ULONG MiUsedSwapPages;
+
+/*
+ * Number of pages that have been reserved for swapping but not yet allocated
+ */
static ULONG MiReservedSwapPages;
+/*
+ * Ratio between reserved and available swap pages, e.g. setting this to five
+ * forces one swap page to be available for every five swap pages that are
+ * reserved. Setting this to zero turns off commit checking altogether.
+ */
+#define MM_PAGEFILE_COMMIT_RATIO (1)
+
+/*
+ * Number of pages that can be used for potentially swapable memory without
+ * pagefile space being reserved. The intention is that this allows smss
+ * to start up and create page files while ordinarily having a commit
+ * ratio of one.
+ */
+#define MM_PAGEFILE_COMMIT_GRACE (256)
+
+static PVOID MmCoreDumpPageFrame = NULL;
+static ULONG MmCoreDumpSize;
+static DUMP_POINTERS MmCoreDumpPointers;
+static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions;
+static ULONG MmCoreDumpPageFile = 0xFFFFFFFF;
+static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping;
+
+ULONG MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE;
+
+/*
+ * Translate between a swap entry and a file and offset pair.
+ */
+#define FILE_FROM_ENTRY(i) ((i) >> 24)
+#define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
+#define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
+
+static BOOLEAN MmSwapSpaceMessage = FALSE;
+
/* FUNCTIONS *****************************************************************/
-VOID MmInitPagingFile(VOID)
+BOOLEAN
+STDCALL
+MmIsFileAPagingFile(PFILE_OBJECT FileObject)
+{
+ ULONG i;
+
+ /* Loop through all the paging files */
+ for (i = 0; i < MiPagingFileCount; i++)
+ {
+ /* Check if this is one of them */
+ if (PagingFileList[i]->FileObject == FileObject) return TRUE;
+ }
+
+ /* Nothing found */
+ return FALSE;
+}
+
+VOID
+NTAPI
+MmShowOutOfSpaceMessagePagingFile(VOID)
+{
+ if (!MmSwapSpaceMessage)
+ {
+ DPRINT1("MM: Out of swap space.\n");
+ MmSwapSpaceMessage = TRUE;
+ }
+}
+
+LARGE_INTEGER STATIC
+MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset)
+{
+ /* Simple binary search */
+ ULONG first, last, mid;
+ first = 0;
+ last = RetrievalPointers->ExtentCount - 1;
+ while (first <= last)
+ {
+ mid = (last - first) / 2 + first;
+ if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart)
+ {
+ if (mid == 0)
+ {
+ Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart;
+ return Offset;
+ }
+ else
+ {
+ if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart)
+ {
+ Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart;
+ return Offset;
+ }
+ last = mid - 1;
+ }
+ }
+ else
+ {
+ if (mid == RetrievalPointers->ExtentCount - 1)
+ {
+ break;
+ }
+ if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart)
+ {
+ Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart;
+ return Offset;
+ }
+ first = mid + 1;
+ }
+ }
+ KEBUGCHECK(0);
+#if defined(__GNUC__)
+
+ return (LARGE_INTEGER)0LL;
+#else
+
+ {
+ const LARGE_INTEGER dummy =
+ {
+ 0
+ };
+ return dummy;
+ }
+#endif
+}
+
+NTSTATUS
+NTAPI
+MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_TYPE Page)
+{
+ ULONG i, offset;
+ LARGE_INTEGER file_offset;
+ IO_STATUS_BLOCK Iosb;
+ NTSTATUS Status;
+ KEVENT Event;
+ UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+ PMDL Mdl = (PMDL)MdlBase;
+
+ DPRINT("MmWriteToSwapPage\n");
+
+ if (SwapEntry == 0)
+ {
+ KEBUGCHECK(0);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ i = FILE_FROM_ENTRY(SwapEntry);
+ offset = OFFSET_FROM_ENTRY(SwapEntry);
+
+ if (i >= MAX_PAGING_FILES)
+ {
+ DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
+ KEBUGCHECK(0);
+ }
+ if (PagingFileList[i]->FileObject == NULL ||
+ PagingFileList[i]->FileObject->DeviceObject == NULL)
+ {
+ DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+ KEBUGCHECK(0);
+ }
+
+ MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+ MmBuildMdlFromPages(Mdl, &Page);
+
+ file_offset.QuadPart = offset * PAGE_SIZE;
+ file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject,
+ Mdl,
+ &file_offset,
+ &Event,
+ &Iosb);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Iosb.Status;
+ }
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ return(Status);
+}
+
+NTSTATUS
+NTAPI
+MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_TYPE Page)
+{
+ ULONG i, offset;
+ LARGE_INTEGER file_offset;
+ IO_STATUS_BLOCK Iosb;
+ NTSTATUS Status;
+ KEVENT Event;
+ UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+ PMDL Mdl = (PMDL)MdlBase;
+
+ DPRINT("MmReadFromSwapPage\n");
+
+ if (SwapEntry == 0)
+ {
+ KEBUGCHECK(0);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ i = FILE_FROM_ENTRY(SwapEntry);
+ offset = OFFSET_FROM_ENTRY(SwapEntry);
+
+ if (i >= MAX_PAGING_FILES)
+ {
+ DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
+ KEBUGCHECK(0);
+ }
+ if (PagingFileList[i]->FileObject == NULL ||
+ PagingFileList[i]->FileObject->DeviceObject == NULL)
+ {
+ DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+ KEBUGCHECK(0);
+ }
+
+ MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+ MmBuildMdlFromPages(Mdl, &Page);
+
+ file_offset.QuadPart = offset * PAGE_SIZE;
+ file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Status = IoPageRead(PagingFileList[i]->FileObject,
+ Mdl,
+ &file_offset,
+ &Event,
+ &Iosb);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Iosb.Status;
+ }
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ return(Status);
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+MmInitPagingFile(VOID)
{
+ ULONG i;
+
KeInitializeSpinLock(&PagingFileListLock);
-
+
MiFreeSwapPages = 0;
MiUsedSwapPages = 0;
MiReservedSwapPages = 0;
+
+ for (i = 0; i < MAX_PAGING_FILES; i++)
+ {
+ PagingFileList[i] = NULL;
+ }
+ MiPagingFileCount = 0;
+
+ /*
+ * Initialize the crash dump support.
+ */
+ if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE)
+ {
+ MmCoreDumpPageFrame = MmAllocateSection(PAGE_SIZE, NULL);
+ if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
+ {
+ MmCoreDumpSize = MmStats.NrTotalPages * 4096 + 1024 * 1024;
+ }
+ else
+ {
+ MmCoreDumpSize = 1024 * 1024;
+ }
+ }
}
-VOID MmReserveSwapPages(ULONG Nr)
+BOOLEAN
+NTAPI
+MmReserveSwapPages(ULONG Nr)
{
KIRQL oldIrql;
-
+ ULONG MiAvailSwapPages;
+
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+ MiAvailSwapPages =
+ (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
MiReservedSwapPages = MiReservedSwapPages + Nr;
- MiFreeSwapPages = MiFreeSwapPages - Nr;
+ if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
+ {
+ KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ return(FALSE);
+ }
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ return(TRUE);
}
-VOID MmDereserveSwapPages(ULONG Nr)
+VOID
+NTAPI
+MmDereserveSwapPages(ULONG Nr)
{
KIRQL oldIrql;
-
+
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
MiReservedSwapPages = MiReservedSwapPages - Nr;
- MiFreeSwapPages = MiFreeSwapPages - Nr;
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
}
-ULONG MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
+static ULONG
+MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
{
KIRQL oldIrql;
- ULONG i;
- ULONG off;
-
+ ULONG i, j;
+
KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
-
+
for (i = 0; i < PagingFile->AllocMapSize; i++)
- {
- off = find_first_zero_bit(PagingFile->AllocMap,
- PagingFile->AllocMapSize * 32);
- clear_bit(off % 32, &PagingFile->AllocMap[off / 32]);
- PagingFile->UsedPages--;
- PagingFile->FreePages++;
- KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
- return(off + 1);
- }
-
+ {
+ for (j = 0; j < 32; j++)
+ {
+ if (!(PagingFile->AllocMap[i] & (1 << j)))
+ {
+ PagingFile->AllocMap[i] |= (1 << j);
+ PagingFile->UsedPages++;
+ PagingFile->FreePages--;
+ KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
+ return((i * 32) + j);
+ }
+ }
+ }
+
KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
- return(0);
+ return(0xFFFFFFFF);
}
-VOID MmFreeSwapPage(SWAPENTRY Entry)
+VOID
+NTAPI
+MmFreeSwapPage(SWAPENTRY Entry)
{
ULONG i;
ULONG off;
KIRQL oldIrql;
-
- i = (Entry >> 24) - 1;
- off = Entry & 0xffffff;
-
+
+ i = FILE_FROM_ENTRY(Entry);
+ off = OFFSET_FROM_ENTRY(Entry);
+
+ if (i >= MAX_PAGING_FILES)
+ {
+ DPRINT1("Bad swap entry 0x%.8X\n", Entry);
+ KEBUGCHECK(0);
+ }
+
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+ if (PagingFileList[i] == NULL)
+ {
+ KEBUGCHECK(0);
+ }
KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
-
- set_bit(off % 32, &PagingFileList[i]->AllocMap[off / 32]);
-
+
+ PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32)));
+
PagingFileList[i]->FreePages++;
PagingFileList[i]->UsedPages--;
-
+
MiFreeSwapPages++;
MiUsedSwapPages--;
-
+
KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
}
-SWAPENTRY MmAllocSwapPage(VOID)
+BOOLEAN
+NTAPI
+MmIsAvailableSwapPage(VOID)
+{
+ return(MiFreeSwapPages > 0);
+}
+
+SWAPENTRY
+NTAPI
+MmAllocSwapPage(VOID)
{
KIRQL oldIrql;
ULONG i;
ULONG off;
SWAPENTRY entry;
-
+
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-
+
if (MiFreeSwapPages == 0)
- {
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
- return(0);
- }
-
+ {
+ KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ return(0);
+ }
+
for (i = 0; i < MAX_PAGING_FILES; i++)
- {
- if (PagingFileList[i] != NULL &&
- PagingFileList[i]->FreePages >= 1)
- {
- off = MiAllocPageFromPagingFile(PagingFileList[i]);
- MiUsedSwapPages++;
- MiFreeSwapPages--;
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-
- entry = ((i+1) << 24) || off;
- return(entry);
- }
- }
-
+ {
+ if (PagingFileList[i] != NULL &&
+ PagingFileList[i]->FreePages >= 1)
+ {
+ off = MiAllocPageFromPagingFile(PagingFileList[i]);
+ if (off == 0xFFFFFFFF)
+ {
+ KEBUGCHECK(0);
+ KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ MiUsedSwapPages++;
+ MiFreeSwapPages--;
+ KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+
+ entry = ENTRY_FROM_FILE_OFFSET(i, off);
+ return(entry);
+ }
+ }
+
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KEBUGCHECK(0);
return(0);
}
-NTSTATUS STDCALL NtCreatePagingFile(IN PUNICODE_STRING PageFileName,
- IN ULONG MinimumSize,
- IN ULONG MaximumSize,
- OUT PULONG ActualSize)
+STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
+MmAllocRetrievelDescriptorList(ULONG Pairs)
+{
+ ULONG Size;
+ PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
+
+ Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
+ RetDescList = ExAllocatePool(NonPagedPool, Size);
+ if (RetDescList)
+ {
+ RtlZeroMemory(RetDescList, Size);
+ }
+
+ return RetDescList;
+}
+
+NTSTATUS STDCALL
+MmDumpToPagingFile(ULONG BugCode,
+ ULONG BugCodeParameter1,
+ ULONG BugCodeParameter2,
+ ULONG BugCodeParameter3,
+ ULONG BugCodeParameter4,
+ PKTRAP_FRAME TrapFrame)
+{
+ PMM_CORE_DUMP_HEADER Headers;
+ NTSTATUS Status;
+ UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+ PMDL Mdl = (PMDL)MdlBase;
+ PETHREAD Thread = PsGetCurrentThread();
+ ULONG_PTR StackSize;
+ PULONG MdlMap;
+ LONGLONG NextOffset = 0;
+ ULONG i;
+ PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+ LARGE_INTEGER DiskOffset;
+
+ if (MmCoreDumpPageFile == 0xFFFFFFFF)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ DbgPrint("\nMM: Dumping core: ");
+
+ /* Prepare the dump headers. */
+ Headers = (PMM_CORE_DUMP_HEADER)MmCoreDumpPageFrame;
+ Headers->Magic = MM_CORE_DUMP_HEADER_MAGIC;
+ Headers->Version = MM_CORE_DUMP_HEADER_VERSION;
+ Headers->Type = MmCoreDumpType;
+ if (TrapFrame != NULL)
+ {
+ if (!(TrapFrame->EFlags & (1 << 17)))
+ {
+ memcpy(&Headers->TrapFrame, TrapFrame,
+ sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
+ }
+ else
+ {
+ memcpy(&Headers->TrapFrame, TrapFrame, sizeof(KTRAP_FRAME));
+ }
+ }
+ Headers->BugCheckCode = BugCode;
+ Headers->BugCheckParameters[0] = BugCodeParameter1;
+ Headers->BugCheckParameters[1] = BugCodeParameter2;
+ Headers->BugCheckParameters[2] = BugCodeParameter3;
+ Headers->BugCheckParameters[3] = BugCodeParameter4;
+ Headers->FaultingStackBase = (PVOID)Thread->Tcb.StackLimit;
+ Headers->FaultingStackSize =
+ StackSize = (ULONG_PTR)Thread->Tcb.StackBase - (ULONG_PTR)Thread->Tcb.StackLimit;
+ Headers->PhysicalMemorySize = MmStats.NrTotalPages * PAGE_SIZE;
+
+ /* Initialize the dump device. */
+ Status = MmCoreDumpFunctions->DumpInit();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MM: Failed to initialize core dump device.\n");
+ return(Status);
+ }
+
+ /* Initialize the MDL. */
+ MmInitializeMdl(Mdl, MmCoreDumpPageFrame, PAGE_SIZE);
+ Mdl->MdlFlags = MDL_PAGES_LOCKED|MDL_IO_PAGE_READ|MDL_SOURCE_IS_NONPAGED_POOL;
+ MdlMap = (PULONG)(Mdl + 1);
+
+
+ /* Initialize the retrieval offsets. */
+ RetrievalPointers = PagingFileList[MmCoreDumpPageFile]->RetrievalPointers;
+
+ /* Dump the header. */
+ MdlMap[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame).QuadPart >> PAGE_SHIFT;
+#if defined(__GNUC__)
+
+ DiskOffset = MmGetOffsetPageFile(RetrievalPointers, (LARGE_INTEGER)0LL);
+#else
+
+ {
+ const LARGE_INTEGER dummy =
+ {
+ 0
+ };
+ DiskOffset = MmGetOffsetPageFile(RetrievalPointers, dummy);
+ }
+#endif
+ DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
+ Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MM: Failed to write core dump header\n.");
+ return(Status);
+ }
+ NextOffset += PAGE_SIZE;
+ ;
+ DbgPrint("00");
+
+
+ /* Write out the contents of physical memory. */
+ if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
+ {
+ for (i = 0; i < MmStats.NrTotalPages; i++)
+ {
+ MdlMap[0] = i;
+ MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame,
+ PAGE_READWRITE,
+ MdlMap,
+ 1);
+#if defined(__GNUC__)
+
+ DiskOffset = MmGetOffsetPageFile(RetrievalPointers,
+ (LARGE_INTEGER)NextOffset);
+#else
+
+ {
+ LARGE_INTEGER dummy;
+ dummy.QuadPart = NextOffset;
+ DiskOffset = MmGetOffsetPageFile(RetrievalPointers, dummy);
+ }
+#endif
+ DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
+ Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
+ MmRawDeleteVirtualMapping(MmCoreDumpPageFrame);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MM: Failed to write page to core dump.\n");
+ return(Status);
+ }
+ if ((i % ((1024*1024) / PAGE_SIZE)) == 0)
+ {
+ DbgPrint("\b\b%.2d", i / ((1024*1024)/PAGE_SIZE));
+ }
+ NextOffset += PAGE_SIZE;
+ }
+ }
+
+ DbgPrint("\n");
+ MmCoreDumpFunctions->DumpFinish();
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL
+MmInitializeCrashDump(HANDLE PageFileHandle, ULONG PageFileNum)
+{
+ PFILE_OBJECT PageFile;
+ PDEVICE_OBJECT PageFileDevice;
+ NTSTATUS Status;
+ PIRP Irp;
+ KEVENT Event;
+ IO_STATUS_BLOCK Iosb;
+ UNICODE_STRING DiskDumpName = RTL_CONSTANT_STRING(L"DiskDump");
+ ANSI_STRING ProcName;
+ PIO_STACK_LOCATION StackPtr;
+ PLDR_DATA_TABLE_ENTRY ModuleObject;
+
+ Status = ZwFsControlFile(PageFileHandle,
+ 0,
+ NULL,
+ NULL,
+ &Iosb,
+ FSCTL_ROS_QUERY_LCN_MAPPING,
+ NULL,
+ 0,
+ &MmCoreDumpLcnMapping,
+ sizeof(ROS_QUERY_LCN_MAPPING));
+ if (!NT_SUCCESS(Status) ||
+ Iosb.Information != sizeof(ROS_QUERY_LCN_MAPPING))
+ {
+ return(Status);
+ }
+
+ /* Get the underlying storage device. */
+ Status =
+ ObReferenceObjectByHandle(PageFileHandle,
+ FILE_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ (PVOID*)&PageFile,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ PageFileDevice = PageFile->Vpb->RealDevice;
+
+ /* Get the dump pointers. */
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS,
+ PageFileDevice,
+ NULL,
+ 0,
+ &MmCoreDumpPointers,
+ sizeof(MmCoreDumpPointers),
+ FALSE,
+ &Event,
+ &Iosb);
+ if(Irp == NULL)
+ {
+ ObDereferenceObject(PageFile);
+ return(STATUS_NO_MEMORY);// tMk - is this correct return code ???
+ }
+
+ StackPtr = IoGetNextIrpStackLocation(Irp);
+ StackPtr->FileObject = PageFile;
+ StackPtr->DeviceObject = PageFileDevice;
+ StackPtr->Parameters.DeviceIoControl.InputBufferLength = 0;
+ StackPtr->Parameters.DeviceIoControl.OutputBufferLength = sizeof(MmCoreDumpPointers);
+
+ Status = IoCallDriver(PageFileDevice,Irp);
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ if (Status != STATUS_SUCCESS ||
+ Iosb.Information != sizeof(MmCoreDumpPointers))
+ {
+ ObDereferenceObject(PageFile);
+ return(Status);
+ }
+
+ /* Load the diskdump driver. */
+ ModuleObject = LdrGetModuleObject(&DiskDumpName);
+ if (ModuleObject == NULL)
+ {
+ return(STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+ RtlInitAnsiString(&ProcName, "DiskDumpFunctions");
+ Status = LdrGetProcedureAddress(ModuleObject->DllBase,
+ &ProcName,
+ 0,
+ (PVOID*)&MmCoreDumpFunctions);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(PageFile);
+ return(Status);
+ }
+
+ /* Prepare for disk dumping. */
+ Status = MmCoreDumpFunctions->DumpPrepare(PageFileDevice,
+ &MmCoreDumpPointers);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(PageFile);
+ return(Status);
+ }
+
+ MmCoreDumpPageFile = PageFileNum;
+ ObDereferenceObject(PageFile);
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL
+NtCreatePagingFile(IN PUNICODE_STRING FileName,
+ IN PLARGE_INTEGER InitialSize,
+ IN PLARGE_INTEGER MaximumSize,
+ IN ULONG Reserved)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
PPAGINGFILE PagingFile;
KIRQL oldIrql;
ULONG AllocMapSize;
+ FILE_FS_SIZE_INFORMATION FsSizeInformation;
+ PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
+ PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
ULONG i;
-
+ ULONG BytesPerAllocationUnit;
+ LARGE_INTEGER Vcn;
+ ULONG ExtentCount;
+ LARGE_INTEGER MaxVcn;
+ ULONG Count;
+ ULONG Size;
+ KPROCESSOR_MODE PreviousMode;
+ UNICODE_STRING CapturedFileName;
+ LARGE_INTEGER SafeInitialSize, SafeMaximumSize;
+
+ DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
+ FileName, InitialSize->QuadPart);
+
+ if (MiPagingFileCount >= MAX_PAGING_FILES)
+ {
+ return(STATUS_TOO_MANY_PAGING_FILES);
+ }
+
+ PreviousMode = ExGetPreviousMode();
+
+ if (PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
+ SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+ else
+ {
+ SafeInitialSize = *InitialSize;
+ SafeMaximumSize = *MaximumSize;
+ }
+
+ /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
+ smaller than the maximum */
+ if (0 != SafeInitialSize.u.HighPart)
+ {
+ return STATUS_INVALID_PARAMETER_2;
+ }
+ if (0 != SafeMaximumSize.u.HighPart)
+ {
+ return STATUS_INVALID_PARAMETER_3;
+ }
+ if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
+ {
+ return STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
+ PreviousMode,
+ FileName);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
InitializeObjectAttributes(&ObjectAttributes,
- PageFileName,
- 0,
- NULL,
- NULL);
- Status = NtCreateFile(&FileHandle,
- FILE_ALL_ACCESS,
- &ObjectAttributes,
- &IoStatus,
- NULL,
- 0,
- 0,
- FILE_OPEN,
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0);
+ &CapturedFileName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = IoCreateFile(&FileHandle,
+ FILE_ALL_ACCESS,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ 0,
+ 0,
+ FILE_OPEN_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0,
+ CreateFileTypeNone,
+ NULL,
+ SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+
+ ReleaseCapturedUnicodeString(&CapturedFileName,
+ PreviousMode);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ Status = ZwQueryVolumeInformationFile(FileHandle,
+ &IoStatus,
+ &FsSizeInformation,
+ sizeof(FILE_FS_SIZE_INFORMATION),
+ FileFsSizeInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(FileHandle);
+ return Status;
+ }
+
+ BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit *
+ FsSizeInformation.BytesPerSector;
+ /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
+ * a problem if the paging file is fragmented. Suppose the first cluster
+ * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
+ * paging file but of another file. We can't write a complete page (4096
+ * bytes) to the physical location of cluster 3042 then. */
+ if (BytesPerAllocationUnit % PAGE_SIZE)
+ {
+ DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
+ BytesPerAllocationUnit, PAGE_SIZE);
+ ZwClose(FileHandle);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = ZwSetInformationFile(FileHandle,
+ &IoStatus,
+ &SafeInitialSize,
+ sizeof(LARGE_INTEGER),
+ FileAllocationInformation);
if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
+ {
+ ZwClose(FileHandle);
+ return(Status);
+ }
+
Status = ObReferenceObjectByHandle(FileHandle,
- FILE_ALL_ACCESS,
- IoFileObjectType,
- UserMode,
- (PVOID*)&FileObject,
- NULL);
+ FILE_ALL_ACCESS,
+ IoFileObjectType,
+ PreviousMode,
+ (PVOID*)&FileObject,
+ NULL);
if (!NT_SUCCESS(Status))
- {
- NtClose(FileHandle);
- return(Status);
- }
-
- NtClose(FileHandle);
-
+ {
+ ZwClose(FileHandle);
+ return(Status);
+ }
+
+ CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
+
+ if (CurrentRetDescList == NULL)
+ {
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_NO_MEMORY);
+ }
+
+#if defined(__GNUC__)
+ Vcn.QuadPart = 0LL;
+#else
+
+ Vcn.QuadPart = 0;
+#endif
+
+ ExtentCount = 0;
+ MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
+ while(1)
+ {
+ Status = ZwFsControlFile(FileHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ FSCTL_GET_RETRIEVAL_POINTERS,
+ &Vcn,
+ sizeof(LARGE_INTEGER),
+ &CurrentRetDescList->RetrievalPointers,
+ sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
+ if (!NT_SUCCESS(Status))
+ {
+ while (RetDescList)
+ {
+ CurrentRetDescList = RetDescList;
+ RetDescList = RetDescList->Next;
+ ExFreePool(CurrentRetDescList);
+ }
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(Status);
+ }
+ ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
+ if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
+ {
+ CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
+ if (CurrentRetDescList->Next == NULL)
+ {
+ while (RetDescList)
+ {
+ CurrentRetDescList = RetDescList;
+ RetDescList = RetDescList->Next;
+ ExFreePool(CurrentRetDescList);
+ }
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_NO_MEMORY);
+ }
+ Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
+ CurrentRetDescList = CurrentRetDescList->Next;
+ }
+ else
+ {
+ break;
+ }
+ }
+
PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
if (PagingFile == NULL)
- {
- ObDereferenceObject(FileObject);
- return(STATUS_NO_MEMORY);
- }
-
+ {
+ while (RetDescList)
+ {
+ CurrentRetDescList = RetDescList;
+ RetDescList = RetDescList->Next;
+ ExFreePool(CurrentRetDescList);
+ }
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_NO_MEMORY);
+ }
+
+ RtlZeroMemory(PagingFile, sizeof(*PagingFile));
+
PagingFile->FileObject = FileObject;
- PagingFile->MaximumSize = PagingFile->CurrentSize = MinimumSize;
- PagingFile->FreePages = MinimumSize;
+ PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
+ PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
+ PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
PagingFile->UsedPages = 0;
KeInitializeSpinLock(&PagingFile->AllocMapLock);
-
- AllocMapSize = (MinimumSize / 32) + 1;
- PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
- AllocMapSize * sizeof(ULONG));
+
+ AllocMapSize = (PagingFile->FreePages / 32) + 1;
+ PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
+ AllocMapSize * sizeof(ULONG));
PagingFile->AllocMapSize = AllocMapSize;
-
+
if (PagingFile->AllocMap == NULL)
- {
- ExFreePool(PagingFile);
- ObDereferenceObject(FileObject);
- return(STATUS_NO_MEMORY);
- }
-
+ {
+ while (RetDescList)
+ {
+ CurrentRetDescList = RetDescList;
+ RetDescList = RetDescList->Next;
+ ExFreePool(CurrentRetDescList);
+ }
+ ExFreePool(PagingFile);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_NO_MEMORY);
+ }
+ DPRINT("ExtentCount: %d\n", ExtentCount);
+ Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
+ PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
+ if (PagingFile->RetrievalPointers == NULL)
+ {
+ while (RetDescList)
+ {
+ CurrentRetDescList = RetDescList;
+ RetDescList = RetDescList->Next;
+ ExFreePool(CurrentRetDescList);
+ }
+ ExFreePool(PagingFile->AllocMap);
+ ExFreePool(PagingFile);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_NO_MEMORY);
+ }
+
+ RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
+ RtlZeroMemory(PagingFile->RetrievalPointers, Size);
+
+ Count = 0;
+ PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
+ PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
+ CurrentRetDescList = RetDescList;
+ while (CurrentRetDescList)
+ {
+ memcpy(&PagingFile->RetrievalPointers->Extents[Count],
+ CurrentRetDescList->RetrievalPointers.Extents,
+ CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
+ Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
+ RetDescList = CurrentRetDescList;
+ CurrentRetDescList = CurrentRetDescList->Next;
+ ExFreePool(RetDescList);
+ }
+
+ if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
+ PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
+ {
+ ExFreePool(PagingFile->RetrievalPointers);
+ ExFreePool(PagingFile->AllocMap);
+ ExFreePool(PagingFile);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Change the entries from lcn's to volume offset's.
+ */
+ PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
+ for (i = 0; i < ExtentCount; i++)
+ {
+ PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
+ PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
+ }
+
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
for (i = 0; i < MAX_PAGING_FILES; i++)
- {
- if (PagingFileList[i] == NULL)
- {
- PagingFileList[i] = PagingFile;
- break;
- }
- }
- MiFreeSwapPages = MiFreeSwapPages + MinimumSize;
+ {
+ if (PagingFileList[i] == NULL)
+ {
+ PagingFileList[i] = PagingFile;
+ break;
+ }
+ }
+ MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
+ MiPagingFileCount++;
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-
+
+ /* Check whether this pagefile can be a crash dump target. */
+ if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE &&
+ PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
+ MmCoreDumpPageFile == 0xFFFFFFFF)
+ {
+ MmInitializeCrashDump(FileHandle, i);
+ }
+ ZwClose(FileHandle);
+
+ MmSwapSpaceMessage = FALSE;
+
return(STATUS_SUCCESS);
}
-
/* EOF */