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 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, MmInitPagingFile)
40 /* TYPES *********************************************************************/
42 typedef struct _PAGINGFILE
44 LIST_ENTRY PagingFileListEntry
;
45 PFILE_OBJECT FileObject
;
46 LARGE_INTEGER MaximumSize
;
47 LARGE_INTEGER CurrentSize
;
51 KSPIN_LOCK AllocMapLock
;
53 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
55 PAGINGFILE
, *PPAGINGFILE
;
57 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
59 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
60 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
62 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
64 /* GLOBALS *******************************************************************/
66 #define PAIRS_PER_RUN (1024)
68 #define MAX_PAGING_FILES (32)
70 /* List of paging files, both used and free */
71 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
73 /* Lock for examining the list of paging files */
74 static KSPIN_LOCK PagingFileListLock
;
76 /* Number of paging files */
77 static ULONG MiPagingFileCount
;
79 /* Number of pages that are available for swapping */
80 ULONG MiFreeSwapPages
;
82 /* Number of pages that have been allocated for swapping */
83 ULONG MiUsedSwapPages
;
86 * Number of pages that have been reserved for swapping but not yet allocated
88 static ULONG MiReservedSwapPages
;
91 * Ratio between reserved and available swap pages, e.g. setting this to five
92 * forces one swap page to be available for every five swap pages that are
93 * reserved. Setting this to zero turns off commit checking altogether.
95 #define MM_PAGEFILE_COMMIT_RATIO (1)
98 * Number of pages that can be used for potentially swapable memory without
99 * pagefile space being reserved. The intention is that this allows smss
100 * to start up and create page files while ordinarily having a commit
103 #define MM_PAGEFILE_COMMIT_GRACE (256)
105 static PVOID MmCoreDumpPageFrame
= NULL
;
106 static ULONG MmCoreDumpSize
;
107 static DUMP_POINTERS MmCoreDumpPointers
;
108 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
109 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
110 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
112 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
115 * Translate between a swap entry and a file and offset pair.
117 #define FILE_FROM_ENTRY(i) ((i) >> 24)
118 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
119 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
121 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
123 /* FUNCTIONS *****************************************************************/
127 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
131 /* Loop through all the paging files */
132 for (i
= 0; i
< MiPagingFileCount
; i
++)
134 /* Check if this is one of them */
135 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
144 MmShowOutOfSpaceMessagePagingFile(VOID
)
146 if (!MmSwapSpaceMessage
)
148 DPRINT1("MM: Out of swap space.\n");
149 MmSwapSpaceMessage
= TRUE
;
154 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
156 /* Simple binary search */
157 ULONG first
, last
, mid
;
159 last
= RetrievalPointers
->ExtentCount
- 1;
160 while (first
<= last
)
162 mid
= (last
- first
) / 2 + first
;
163 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
167 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
172 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
174 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
182 if (mid
== RetrievalPointers
->ExtentCount
- 1)
186 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
188 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
195 #if defined(__GNUC__)
197 return (LARGE_INTEGER
)0LL;
201 const LARGE_INTEGER dummy
=
212 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
215 LARGE_INTEGER file_offset
;
216 IO_STATUS_BLOCK Iosb
;
219 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
220 PMDL Mdl
= (PMDL
)MdlBase
;
222 DPRINT("MmWriteToSwapPage\n");
227 return(STATUS_UNSUCCESSFUL
);
230 i
= FILE_FROM_ENTRY(SwapEntry
);
231 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
233 if (i
>= MAX_PAGING_FILES
)
235 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
238 if (PagingFileList
[i
]->FileObject
== NULL
||
239 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
241 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
245 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
246 MmBuildMdlFromPages(Mdl
, &Page
);
248 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
249 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
251 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
252 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
257 if (Status
== STATUS_PENDING
)
259 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
260 Status
= Iosb
.Status
;
262 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
268 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
271 LARGE_INTEGER file_offset
;
272 IO_STATUS_BLOCK Iosb
;
275 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
276 PMDL Mdl
= (PMDL
)MdlBase
;
278 DPRINT("MmReadFromSwapPage\n");
283 return(STATUS_UNSUCCESSFUL
);
286 i
= FILE_FROM_ENTRY(SwapEntry
);
287 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
289 if (i
>= MAX_PAGING_FILES
)
291 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
294 if (PagingFileList
[i
]->FileObject
== NULL
||
295 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
297 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
301 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
302 MmBuildMdlFromPages(Mdl
, &Page
);
304 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
305 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
307 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
308 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
313 if (Status
== STATUS_PENDING
)
315 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
316 Status
= Iosb
.Status
;
318 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
325 MmInitPagingFile(VOID
)
329 KeInitializeSpinLock(&PagingFileListLock
);
333 MiReservedSwapPages
= 0;
335 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
337 PagingFileList
[i
] = NULL
;
339 MiPagingFileCount
= 0;
342 * Initialize the crash dump support.
344 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
346 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
347 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
349 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
353 MmCoreDumpSize
= 1024 * 1024;
360 MmReserveSwapPages(ULONG Nr
)
363 ULONG MiAvailSwapPages
;
365 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
367 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
368 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
369 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
371 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
374 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
380 MmDereserveSwapPages(ULONG Nr
)
384 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
385 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
386 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
390 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
395 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
397 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
399 for (j
= 0; j
< 32; j
++)
401 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
403 PagingFile
->AllocMap
[i
] |= (1 << j
);
404 PagingFile
->UsedPages
++;
405 PagingFile
->FreePages
--;
406 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
407 return((i
* 32) + j
);
412 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
418 MmFreeSwapPage(SWAPENTRY Entry
)
424 i
= FILE_FROM_ENTRY(Entry
);
425 off
= OFFSET_FROM_ENTRY(Entry
);
427 if (i
>= MAX_PAGING_FILES
)
429 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
433 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
434 if (PagingFileList
[i
] == NULL
)
438 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
440 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
442 PagingFileList
[i
]->FreePages
++;
443 PagingFileList
[i
]->UsedPages
--;
448 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
449 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
454 MmIsAvailableSwapPage(VOID
)
456 return(MiFreeSwapPages
> 0);
461 MmAllocSwapPage(VOID
)
468 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
470 if (MiFreeSwapPages
== 0)
472 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
476 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
478 if (PagingFileList
[i
] != NULL
&&
479 PagingFileList
[i
]->FreePages
>= 1)
481 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
482 if (off
== 0xFFFFFFFF)
485 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
486 return(STATUS_UNSUCCESSFUL
);
490 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
492 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
497 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
502 STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
503 MmAllocRetrievelDescriptorList(ULONG Pairs
)
506 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
508 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
509 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
512 RtlZeroMemory(RetDescList
, Size
);
519 MmDumpToPagingFile(ULONG BugCode
,
520 ULONG BugCodeParameter1
,
521 ULONG BugCodeParameter2
,
522 ULONG BugCodeParameter3
,
523 ULONG BugCodeParameter4
,
524 PKTRAP_FRAME TrapFrame
)
526 PMM_CORE_DUMP_HEADER Headers
;
528 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
529 PMDL Mdl
= (PMDL
)MdlBase
;
530 PETHREAD Thread
= PsGetCurrentThread();
533 LONGLONG NextOffset
= 0;
535 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
536 LARGE_INTEGER DiskOffset
;
538 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
540 return(STATUS_UNSUCCESSFUL
);
543 DbgPrint("\nMM: Dumping core: ");
545 /* Prepare the dump headers. */
546 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
547 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
548 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
549 Headers
->Type
= MmCoreDumpType
;
550 if (TrapFrame
!= NULL
)
552 if (!(TrapFrame
->EFlags
& (1 << 17)))
554 memcpy(&Headers
->TrapFrame
, TrapFrame
,
555 sizeof(KTRAP_FRAME
) - (4 * sizeof(DWORD
)));
559 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
562 Headers
->BugCheckCode
= BugCode
;
563 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
564 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
565 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
566 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
567 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
568 Headers
->FaultingStackSize
=
569 StackSize
= (ULONG_PTR
)Thread
->Tcb
.StackBase
- (ULONG_PTR
)Thread
->Tcb
.StackLimit
;
570 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
572 /* Initialize the dump device. */
573 Status
= MmCoreDumpFunctions
->DumpInit();
574 if (!NT_SUCCESS(Status
))
576 DPRINT1("MM: Failed to initialize core dump device.\n");
580 /* Initialize the MDL. */
581 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
582 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
583 MdlMap
= (PULONG
)(Mdl
+ 1);
586 /* Initialize the retrieval offsets. */
587 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
589 /* Dump the header. */
590 MdlMap
[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
;
591 #if defined(__GNUC__)
593 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
597 const LARGE_INTEGER dummy
=
601 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
604 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
605 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
606 if (!NT_SUCCESS(Status
))
608 DPRINT1("MM: Failed to write core dump header\n.");
611 NextOffset
+= PAGE_SIZE
;
616 /* Write out the contents of physical memory. */
617 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
619 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
622 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
626 #if defined(__GNUC__)
628 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
629 (LARGE_INTEGER
)NextOffset
);
634 dummy
.QuadPart
= NextOffset
;
635 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
638 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
639 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
640 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
641 if (!NT_SUCCESS(Status
))
643 DPRINT1("MM: Failed to write page to core dump.\n");
646 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
648 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
650 NextOffset
+= PAGE_SIZE
;
655 MmCoreDumpFunctions
->DumpFinish();
656 return(STATUS_SUCCESS
);
660 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
662 PFILE_OBJECT PageFile
;
663 PDEVICE_OBJECT PageFileDevice
;
667 IO_STATUS_BLOCK Iosb
;
668 UNICODE_STRING DiskDumpName
= RTL_CONSTANT_STRING(L
"DiskDump");
669 ANSI_STRING ProcName
;
670 PIO_STACK_LOCATION StackPtr
;
671 PLDR_DATA_TABLE_ENTRY ModuleObject
;
673 Status
= ZwFsControlFile(PageFileHandle
,
678 FSCTL_ROS_QUERY_LCN_MAPPING
,
681 &MmCoreDumpLcnMapping
,
682 sizeof(ROS_QUERY_LCN_MAPPING
));
683 if (!NT_SUCCESS(Status
) ||
684 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
689 /* Get the underlying storage device. */
691 ObReferenceObjectByHandle(PageFileHandle
,
697 if (!NT_SUCCESS(Status
))
702 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
704 /* Get the dump pointers. */
705 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
706 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
711 sizeof(MmCoreDumpPointers
),
717 ObDereferenceObject(PageFile
);
718 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
721 StackPtr
= IoGetNextIrpStackLocation(Irp
);
722 StackPtr
->FileObject
= PageFile
;
723 StackPtr
->DeviceObject
= PageFileDevice
;
724 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
725 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
727 Status
= IoCallDriver(PageFileDevice
,Irp
);
728 if (Status
== STATUS_PENDING
)
730 Status
= KeWaitForSingleObject(&Event
,
736 if (Status
!= STATUS_SUCCESS
||
737 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
739 ObDereferenceObject(PageFile
);
743 /* Load the diskdump driver. */
744 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
745 if (ModuleObject
== NULL
)
747 return(STATUS_OBJECT_NAME_NOT_FOUND
);
749 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
750 Status
= LdrGetProcedureAddress(ModuleObject
->DllBase
,
753 (PVOID
*)&MmCoreDumpFunctions
);
754 if (!NT_SUCCESS(Status
))
756 ObDereferenceObject(PageFile
);
760 /* Prepare for disk dumping. */
761 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
762 &MmCoreDumpPointers
);
763 if (!NT_SUCCESS(Status
))
765 ObDereferenceObject(PageFile
);
769 MmCoreDumpPageFile
= PageFileNum
;
770 ObDereferenceObject(PageFile
);
771 return(STATUS_SUCCESS
);
775 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
776 IN PLARGE_INTEGER InitialSize
,
777 IN PLARGE_INTEGER MaximumSize
,
781 OBJECT_ATTRIBUTES ObjectAttributes
;
783 IO_STATUS_BLOCK IoStatus
;
784 PFILE_OBJECT FileObject
;
785 PPAGINGFILE PagingFile
;
788 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
789 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
790 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
792 ULONG BytesPerAllocationUnit
;
795 LARGE_INTEGER MaxVcn
;
798 KPROCESSOR_MODE PreviousMode
;
799 UNICODE_STRING CapturedFileName
;
800 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
802 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
803 FileName
, InitialSize
->QuadPart
);
805 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
807 return(STATUS_TOO_MANY_PAGING_FILES
);
810 PreviousMode
= ExGetPreviousMode();
812 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
815 if (!NT_SUCCESS(Status
))
819 if (PreviousMode
!= KernelMode
)
823 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
824 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
828 Status
= _SEH_GetExceptionCode();
832 if (!NT_SUCCESS(Status
))
834 ReleaseCapturedUnicodeString(&CapturedFileName
,
841 SafeInitialSize
= *InitialSize
;
842 SafeMaximumSize
= *MaximumSize
;
845 InitializeObjectAttributes(&ObjectAttributes
,
851 Status
= IoCreateFile(&FileHandle
,
859 FILE_SYNCHRONOUS_IO_NONALERT
,
864 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
866 ReleaseCapturedUnicodeString(&CapturedFileName
,
868 if (!NT_SUCCESS(Status
))
873 Status
= ZwQueryVolumeInformationFile(FileHandle
,
876 sizeof(FILE_FS_SIZE_INFORMATION
),
877 FileFsSizeInformation
);
878 if (!NT_SUCCESS(Status
))
884 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
* FsSizeInformation
.BytesPerSector
;
885 if (BytesPerAllocationUnit
% PAGE_SIZE
)
888 return STATUS_UNSUCCESSFUL
;
891 Status
= ZwSetInformationFile(FileHandle
,
894 sizeof(LARGE_INTEGER
),
895 FileAllocationInformation
);
896 if (!NT_SUCCESS(Status
))
902 Status
= ObReferenceObjectByHandle(FileHandle
,
908 if (!NT_SUCCESS(Status
))
914 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
916 if (CurrentRetDescList
== NULL
)
918 ObDereferenceObject(FileObject
);
920 return(STATUS_NO_MEMORY
);
923 #if defined(__GNUC__)
931 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
934 Status
= ZwFsControlFile(FileHandle
,
939 FSCTL_GET_RETRIEVAL_POINTERS
,
941 sizeof(LARGE_INTEGER
),
942 &CurrentRetDescList
->RetrievalPointers
,
943 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
944 if (!NT_SUCCESS(Status
))
948 CurrentRetDescList
= RetDescList
;
949 RetDescList
= RetDescList
->Next
;
950 ExFreePool(CurrentRetDescList
);
952 ObDereferenceObject(FileObject
);
956 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
957 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
959 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
960 if (CurrentRetDescList
->Next
== NULL
)
964 CurrentRetDescList
= RetDescList
;
965 RetDescList
= RetDescList
->Next
;
966 ExFreePool(CurrentRetDescList
);
968 ObDereferenceObject(FileObject
);
970 return(STATUS_NO_MEMORY
);
972 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
973 CurrentRetDescList
= CurrentRetDescList
->Next
;
981 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
982 if (PagingFile
== NULL
)
986 CurrentRetDescList
= RetDescList
;
987 RetDescList
= RetDescList
->Next
;
988 ExFreePool(CurrentRetDescList
);
990 ObDereferenceObject(FileObject
);
992 return(STATUS_NO_MEMORY
);
995 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
997 PagingFile
->FileObject
= FileObject
;
998 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
999 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
1000 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
1001 PagingFile
->UsedPages
= 0;
1002 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
1004 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
1005 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
1006 AllocMapSize
* sizeof(ULONG
));
1007 PagingFile
->AllocMapSize
= AllocMapSize
;
1009 if (PagingFile
->AllocMap
== NULL
)
1013 CurrentRetDescList
= RetDescList
;
1014 RetDescList
= RetDescList
->Next
;
1015 ExFreePool(CurrentRetDescList
);
1017 ExFreePool(PagingFile
);
1018 ObDereferenceObject(FileObject
);
1019 ZwClose(FileHandle
);
1020 return(STATUS_NO_MEMORY
);
1022 DPRINT("ExtentCount: %d\n", ExtentCount
);
1023 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
1024 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
1025 if (PagingFile
->RetrievalPointers
== NULL
)
1029 CurrentRetDescList
= RetDescList
;
1030 RetDescList
= RetDescList
->Next
;
1031 ExFreePool(CurrentRetDescList
);
1033 ExFreePool(PagingFile
->AllocMap
);
1034 ExFreePool(PagingFile
);
1035 ObDereferenceObject(FileObject
);
1036 ZwClose(FileHandle
);
1037 return(STATUS_NO_MEMORY
);
1040 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
1041 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
1044 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
1045 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
1046 CurrentRetDescList
= RetDescList
;
1047 while (CurrentRetDescList
)
1049 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
1050 CurrentRetDescList
->RetrievalPointers
.Extents
,
1051 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
1052 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1053 RetDescList
= CurrentRetDescList
;
1054 CurrentRetDescList
= CurrentRetDescList
->Next
;
1055 ExFreePool(RetDescList
);
1058 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
1059 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
1061 ExFreePool(PagingFile
->RetrievalPointers
);
1062 ExFreePool(PagingFile
->AllocMap
);
1063 ExFreePool(PagingFile
);
1064 ObDereferenceObject(FileObject
);
1065 ZwClose(FileHandle
);
1066 return(STATUS_UNSUCCESSFUL
);
1070 * Change the entries from lcn's to volume offset's.
1072 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
1073 for (i
= 0; i
< ExtentCount
; i
++)
1075 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
1076 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
1079 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1080 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1082 if (PagingFileList
[i
] == NULL
)
1084 PagingFileList
[i
] = PagingFile
;
1088 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1089 MiPagingFileCount
++;
1090 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1092 /* Check whether this pagefile can be a crash dump target. */
1093 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1094 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1095 MmCoreDumpPageFile
== 0xFFFFFFFF)
1097 MmInitializeCrashDump(FileHandle
, i
);
1099 ZwClose(FileHandle
);
1101 MmSwapSpaceMessage
= FALSE
;
1103 return(STATUS_SUCCESS
);