3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/pagefile.c
23 * PURPOSE: Paging file functions
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
33 #include <internal/debug.h>
35 /* TYPES *********************************************************************/
37 typedef struct _PAGINGFILE
39 LIST_ENTRY PagingFileListEntry
;
40 PFILE_OBJECT FileObject
;
41 LARGE_INTEGER MaximumSize
;
42 LARGE_INTEGER CurrentSize
;
46 KSPIN_LOCK AllocMapLock
;
48 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
50 PAGINGFILE
, *PPAGINGFILE
;
52 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
54 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
55 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
57 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
59 /* GLOBALS *******************************************************************/
61 #define PAIRS_PER_RUN (1024)
63 #define MAX_PAGING_FILES (32)
65 /* List of paging files, both used and free */
66 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
68 /* Lock for examining the list of paging files */
69 static KSPIN_LOCK PagingFileListLock
;
71 /* Number of paging files */
72 static ULONG MiPagingFileCount
;
74 /* Number of pages that are available for swapping */
75 ULONG MiFreeSwapPages
;
77 /* Number of pages that have been allocated for swapping */
78 ULONG MiUsedSwapPages
;
81 * Number of pages that have been reserved for swapping but not yet allocated
83 static ULONG MiReservedSwapPages
;
86 * Ratio between reserved and available swap pages, e.g. setting this to five
87 * forces one swap page to be available for every five swap pages that are
88 * reserved. Setting this to zero turns off commit checking altogether.
90 #define MM_PAGEFILE_COMMIT_RATIO (1)
93 * Number of pages that can be used for potentially swapable memory without
94 * pagefile space being reserved. The intention is that this allows smss
95 * to start up and create page files while ordinarily having a commit
98 #define MM_PAGEFILE_COMMIT_GRACE (256)
100 static PVOID MmCoreDumpPageFrame
= NULL
;
101 static ULONG MmCoreDumpSize
;
102 static DUMP_POINTERS MmCoreDumpPointers
;
103 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
104 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
105 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
107 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
110 * Translate between a swap entry and a file and offset pair.
112 #define FILE_FROM_ENTRY(i) ((i) >> 24)
113 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
114 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
116 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
118 /* FUNCTIONS *****************************************************************/
122 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
126 /* Loop through all the paging files */
127 for (i
= 0; i
< MiPagingFileCount
; i
++)
129 /* Check if this is one of them */
130 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
138 MmShowOutOfSpaceMessagePagingFile(VOID
)
140 if (!MmSwapSpaceMessage
)
142 DPRINT1("MM: Out of swap space.\n");
143 MmSwapSpaceMessage
= TRUE
;
148 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
150 /* Simple binary search */
151 ULONG first
, last
, mid
;
153 last
= RetrievalPointers
->ExtentCount
- 1;
154 while (first
<= last
)
156 mid
= (last
- first
) / 2 + first
;
157 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
161 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
166 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
168 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
176 if (mid
== RetrievalPointers
->ExtentCount
- 1)
180 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
182 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
189 #if defined(__GNUC__)
191 return (LARGE_INTEGER
)0LL;
195 const LARGE_INTEGER dummy
=
204 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
207 LARGE_INTEGER file_offset
;
208 IO_STATUS_BLOCK Iosb
;
211 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
212 PMDL Mdl
= (PMDL
)MdlBase
;
214 DPRINT("MmWriteToSwapPage\n");
219 return(STATUS_UNSUCCESSFUL
);
222 i
= FILE_FROM_ENTRY(SwapEntry
);
223 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
225 if (i
>= MAX_PAGING_FILES
)
227 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
230 if (PagingFileList
[i
]->FileObject
== NULL
||
231 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
233 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
237 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
238 MmBuildMdlFromPages(Mdl
, &Page
);
240 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
241 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
243 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
244 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
249 if (Status
== STATUS_PENDING
)
251 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
252 Status
= Iosb
.Status
;
254 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
258 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
261 LARGE_INTEGER file_offset
;
262 IO_STATUS_BLOCK Iosb
;
265 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
266 PMDL Mdl
= (PMDL
)MdlBase
;
268 DPRINT("MmReadFromSwapPage\n");
273 return(STATUS_UNSUCCESSFUL
);
276 i
= FILE_FROM_ENTRY(SwapEntry
);
277 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
279 if (i
>= MAX_PAGING_FILES
)
281 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
284 if (PagingFileList
[i
]->FileObject
== NULL
||
285 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
287 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
291 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
292 MmBuildMdlFromPages(Mdl
, &Page
);
294 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
295 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
297 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
298 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
303 if (Status
== STATUS_PENDING
)
305 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
306 Status
= Iosb
.Status
;
308 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
313 MmInitPagingFile(VOID
)
317 KeInitializeSpinLock(&PagingFileListLock
);
321 MiReservedSwapPages
= 0;
323 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
325 PagingFileList
[i
] = NULL
;
327 MiPagingFileCount
= 0;
330 * Initialize the crash dump support.
332 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
334 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
335 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
337 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
341 MmCoreDumpSize
= 1024 * 1024;
347 MmReserveSwapPages(ULONG Nr
)
350 ULONG MiAvailSwapPages
;
352 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
354 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
355 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
356 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
358 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
361 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
366 MmDereserveSwapPages(ULONG Nr
)
370 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
371 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
372 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
376 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
381 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
383 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
385 for (j
= 0; j
< 32; j
++)
387 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
389 PagingFile
->AllocMap
[i
] |= (1 << j
);
390 PagingFile
->UsedPages
++;
391 PagingFile
->FreePages
--;
392 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
393 return((i
* 32) + j
);
398 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
403 MmFreeSwapPage(SWAPENTRY Entry
)
409 i
= FILE_FROM_ENTRY(Entry
);
410 off
= OFFSET_FROM_ENTRY(Entry
);
412 if (i
>= MAX_PAGING_FILES
)
414 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
418 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
419 if (PagingFileList
[i
] == NULL
)
423 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
425 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
427 PagingFileList
[i
]->FreePages
++;
428 PagingFileList
[i
]->UsedPages
--;
433 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
434 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
438 MmIsAvailableSwapPage(VOID
)
440 return(MiFreeSwapPages
> 0);
444 MmAllocSwapPage(VOID
)
451 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
453 if (MiFreeSwapPages
== 0)
455 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
459 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
461 if (PagingFileList
[i
] != NULL
&&
462 PagingFileList
[i
]->FreePages
>= 1)
464 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
465 if (off
== 0xFFFFFFFF)
468 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
469 return(STATUS_UNSUCCESSFUL
);
473 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
475 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
480 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
485 STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
486 MmAllocRetrievelDescriptorList(ULONG Pairs
)
489 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
491 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
492 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
495 RtlZeroMemory(RetDescList
, Size
);
502 MmDumpToPagingFile(ULONG BugCode
,
503 ULONG BugCodeParameter1
,
504 ULONG BugCodeParameter2
,
505 ULONG BugCodeParameter3
,
506 ULONG BugCodeParameter4
,
507 PKTRAP_FRAME TrapFrame
)
509 PMM_CORE_DUMP_HEADER Headers
;
511 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
512 PMDL Mdl
= (PMDL
)MdlBase
;
513 PETHREAD Thread
= PsGetCurrentThread();
516 LONGLONG NextOffset
= 0;
518 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
519 LARGE_INTEGER DiskOffset
;
521 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
523 return(STATUS_UNSUCCESSFUL
);
526 DbgPrint("\nMM: Dumping core: ");
528 /* Prepare the dump headers. */
529 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
530 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
531 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
532 Headers
->Type
= MmCoreDumpType
;
533 if (TrapFrame
!= NULL
)
535 if (!(TrapFrame
->Eflags
& (1 << 17)))
537 memcpy(&Headers
->TrapFrame
, TrapFrame
,
538 sizeof(KTRAP_FRAME
) - (4 * sizeof(DWORD
)));
542 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
545 Headers
->BugCheckCode
= BugCode
;
546 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
547 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
548 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
549 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
550 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
551 Headers
->FaultingStackSize
=
552 StackSize
= (ULONG_PTR
)Thread
->Tcb
.StackBase
- (ULONG_PTR
)Thread
->Tcb
.StackLimit
;
553 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
555 /* Initialize the dump device. */
556 Status
= MmCoreDumpFunctions
->DumpInit();
557 if (!NT_SUCCESS(Status
))
559 DPRINT1("MM: Failed to initialize core dump device.\n");
563 /* Initialize the MDL. */
564 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
565 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
566 MdlMap
= (PULONG
)(Mdl
+ 1);
569 /* Initialize the retrieval offsets. */
570 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
572 /* Dump the header. */
573 MdlMap
[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
;
574 #if defined(__GNUC__)
576 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
580 const LARGE_INTEGER dummy
=
584 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
587 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
588 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
589 if (!NT_SUCCESS(Status
))
591 DPRINT1("MM: Failed to write core dump header\n.");
594 NextOffset
+= PAGE_SIZE
;
599 /* Write out the contents of physical memory. */
600 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
602 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
605 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
609 #if defined(__GNUC__)
611 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
612 (LARGE_INTEGER
)NextOffset
);
617 dummy
.QuadPart
= NextOffset
;
618 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
621 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
622 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
623 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
624 if (!NT_SUCCESS(Status
))
626 DPRINT1("MM: Failed to write page to core dump.\n");
629 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
631 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
633 NextOffset
+= PAGE_SIZE
;
638 MmCoreDumpFunctions
->DumpFinish();
639 return(STATUS_SUCCESS
);
643 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
645 PFILE_OBJECT PageFile
;
646 PDEVICE_OBJECT PageFileDevice
;
650 IO_STATUS_BLOCK Iosb
;
651 UNICODE_STRING DiskDumpName
= RTL_CONSTANT_STRING(L
"DiskDump");
652 ANSI_STRING ProcName
;
653 PIO_STACK_LOCATION StackPtr
;
654 PLDR_DATA_TABLE_ENTRY ModuleObject
;
656 Status
= ZwFsControlFile(PageFileHandle
,
661 FSCTL_ROS_QUERY_LCN_MAPPING
,
664 &MmCoreDumpLcnMapping
,
665 sizeof(ROS_QUERY_LCN_MAPPING
));
666 if (!NT_SUCCESS(Status
) ||
667 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
672 /* Get the underlying storage device. */
674 ObReferenceObjectByHandle(PageFileHandle
,
680 if (!NT_SUCCESS(Status
))
685 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
687 /* Get the dump pointers. */
688 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
689 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
694 sizeof(MmCoreDumpPointers
),
700 ObDereferenceObject(PageFile
);
701 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
704 StackPtr
= IoGetNextIrpStackLocation(Irp
);
705 StackPtr
->FileObject
= PageFile
;
706 StackPtr
->DeviceObject
= PageFileDevice
;
707 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
708 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
710 Status
= IoCallDriver(PageFileDevice
,Irp
);
711 if (Status
== STATUS_PENDING
)
713 Status
= KeWaitForSingleObject(&Event
,
719 if (Status
!= STATUS_SUCCESS
||
720 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
722 ObDereferenceObject(PageFile
);
726 /* Load the diskdump driver. */
727 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
728 if (ModuleObject
== NULL
)
730 return(STATUS_OBJECT_NAME_NOT_FOUND
);
732 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
733 Status
= LdrGetProcedureAddress(ModuleObject
->DllBase
,
736 (PVOID
*)&MmCoreDumpFunctions
);
737 if (!NT_SUCCESS(Status
))
739 ObDereferenceObject(PageFile
);
743 /* Prepare for disk dumping. */
744 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
745 &MmCoreDumpPointers
);
746 if (!NT_SUCCESS(Status
))
748 ObDereferenceObject(PageFile
);
752 MmCoreDumpPageFile
= PageFileNum
;
753 ObDereferenceObject(PageFile
);
754 return(STATUS_SUCCESS
);
758 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
759 IN PLARGE_INTEGER InitialSize
,
760 IN PLARGE_INTEGER MaximumSize
,
764 OBJECT_ATTRIBUTES ObjectAttributes
;
766 IO_STATUS_BLOCK IoStatus
;
767 PFILE_OBJECT FileObject
;
768 PPAGINGFILE PagingFile
;
771 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
772 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
773 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
775 ULONG BytesPerAllocationUnit
;
778 LARGE_INTEGER MaxVcn
;
781 KPROCESSOR_MODE PreviousMode
;
782 UNICODE_STRING CapturedFileName
;
783 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
785 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
786 FileName
, InitialSize
->QuadPart
);
788 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
790 return(STATUS_TOO_MANY_PAGING_FILES
);
793 PreviousMode
= ExGetPreviousMode();
795 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
798 if (!NT_SUCCESS(Status
))
802 if (PreviousMode
!= KernelMode
)
806 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
807 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
811 Status
= _SEH_GetExceptionCode();
815 if (!NT_SUCCESS(Status
))
817 ReleaseCapturedUnicodeString(&CapturedFileName
,
824 SafeInitialSize
= *InitialSize
;
825 SafeMaximumSize
= *MaximumSize
;
828 InitializeObjectAttributes(&ObjectAttributes
,
834 Status
= IoCreateFile(&FileHandle
,
842 FILE_SYNCHRONOUS_IO_NONALERT
,
847 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
849 ReleaseCapturedUnicodeString(&CapturedFileName
,
851 if (!NT_SUCCESS(Status
))
856 Status
= ZwQueryVolumeInformationFile(FileHandle
,
859 sizeof(FILE_FS_SIZE_INFORMATION
),
860 FileFsSizeInformation
);
861 if (!NT_SUCCESS(Status
))
867 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
* FsSizeInformation
.BytesPerSector
;
868 if (BytesPerAllocationUnit
% PAGE_SIZE
)
871 return STATUS_UNSUCCESSFUL
;
874 Status
= ZwSetInformationFile(FileHandle
,
877 sizeof(LARGE_INTEGER
),
878 FileAllocationInformation
);
879 if (!NT_SUCCESS(Status
))
885 Status
= ObReferenceObjectByHandle(FileHandle
,
891 if (!NT_SUCCESS(Status
))
897 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
899 if (CurrentRetDescList
== NULL
)
901 ObDereferenceObject(FileObject
);
903 return(STATUS_NO_MEMORY
);
906 #if defined(__GNUC__)
914 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
917 Status
= ZwFsControlFile(FileHandle
,
922 FSCTL_GET_RETRIEVAL_POINTERS
,
924 sizeof(LARGE_INTEGER
),
925 &CurrentRetDescList
->RetrievalPointers
,
926 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
927 if (!NT_SUCCESS(Status
))
931 CurrentRetDescList
= RetDescList
;
932 RetDescList
= RetDescList
->Next
;
933 ExFreePool(CurrentRetDescList
);
935 ObDereferenceObject(FileObject
);
939 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
940 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
942 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
943 if (CurrentRetDescList
->Next
== NULL
)
947 CurrentRetDescList
= RetDescList
;
948 RetDescList
= RetDescList
->Next
;
949 ExFreePool(CurrentRetDescList
);
951 ObDereferenceObject(FileObject
);
953 return(STATUS_NO_MEMORY
);
955 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
956 CurrentRetDescList
= CurrentRetDescList
->Next
;
964 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
965 if (PagingFile
== NULL
)
969 CurrentRetDescList
= RetDescList
;
970 RetDescList
= RetDescList
->Next
;
971 ExFreePool(CurrentRetDescList
);
973 ObDereferenceObject(FileObject
);
975 return(STATUS_NO_MEMORY
);
978 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
980 PagingFile
->FileObject
= FileObject
;
981 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
982 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
983 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
984 PagingFile
->UsedPages
= 0;
985 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
987 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
988 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
989 AllocMapSize
* sizeof(ULONG
));
990 PagingFile
->AllocMapSize
= AllocMapSize
;
992 if (PagingFile
->AllocMap
== NULL
)
996 CurrentRetDescList
= RetDescList
;
997 RetDescList
= RetDescList
->Next
;
998 ExFreePool(CurrentRetDescList
);
1000 ExFreePool(PagingFile
);
1001 ObDereferenceObject(FileObject
);
1002 ZwClose(FileHandle
);
1003 return(STATUS_NO_MEMORY
);
1005 DPRINT("ExtentCount: %d\n", ExtentCount
);
1006 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
1007 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
1008 if (PagingFile
->RetrievalPointers
== NULL
)
1012 CurrentRetDescList
= RetDescList
;
1013 RetDescList
= RetDescList
->Next
;
1014 ExFreePool(CurrentRetDescList
);
1016 ExFreePool(PagingFile
->AllocMap
);
1017 ExFreePool(PagingFile
);
1018 ObDereferenceObject(FileObject
);
1019 ZwClose(FileHandle
);
1020 return(STATUS_NO_MEMORY
);
1023 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
1024 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
1027 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
1028 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
1029 CurrentRetDescList
= RetDescList
;
1030 while (CurrentRetDescList
)
1032 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
1033 CurrentRetDescList
->RetrievalPointers
.Extents
,
1034 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
1035 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1036 RetDescList
= CurrentRetDescList
;
1037 CurrentRetDescList
= CurrentRetDescList
->Next
;
1038 ExFreePool(RetDescList
);
1041 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
1042 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
1044 ExFreePool(PagingFile
->RetrievalPointers
);
1045 ExFreePool(PagingFile
->AllocMap
);
1046 ExFreePool(PagingFile
);
1047 ObDereferenceObject(FileObject
);
1048 ZwClose(FileHandle
);
1049 return(STATUS_UNSUCCESSFUL
);
1053 * Change the entries from lcn's to volume offset's.
1055 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
1056 for (i
= 0; i
< ExtentCount
; i
++)
1058 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
1059 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
1062 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1063 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1065 if (PagingFileList
[i
] == NULL
)
1067 PagingFileList
[i
] = PagingFile
;
1071 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1072 MiPagingFileCount
++;
1073 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1075 /* Check whether this pagefile can be a crash dump target. */
1076 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1077 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1078 MmCoreDumpPageFile
== 0xFFFFFFFF)
1080 MmInitializeCrashDump(FileHandle
, i
);
1082 ZwClose(FileHandle
);
1084 MmSwapSpaceMessage
= FALSE
;
1086 return(STATUS_SUCCESS
);