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.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/pagefile.c
22 * PURPOSE: Paging file functions
23 * PROGRAMMER: David Welch (welch@mcmail.com)
28 /* INCLUDES *****************************************************************/
32 #include <internal/debug.h>
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, MmInitPagingFile)
40 MiFindExportedRoutineByName(IN PVOID DllBase
,
41 IN PANSI_STRING ExportName
);
43 /* TYPES *********************************************************************/
45 typedef struct _PAGINGFILE
47 LIST_ENTRY PagingFileListEntry
;
48 PFILE_OBJECT FileObject
;
49 LARGE_INTEGER MaximumSize
;
50 LARGE_INTEGER CurrentSize
;
54 KSPIN_LOCK AllocMapLock
;
56 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
58 PAGINGFILE
, *PPAGINGFILE
;
60 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
62 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
63 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
65 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
67 /* GLOBALS *******************************************************************/
69 #define PAIRS_PER_RUN (1024)
71 #define MAX_PAGING_FILES (32)
73 /* List of paging files, both used and free */
74 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
76 /* Lock for examining the list of paging files */
77 static KSPIN_LOCK PagingFileListLock
;
79 /* Number of paging files */
80 static ULONG MiPagingFileCount
;
82 /* Number of pages that are available for swapping */
83 ULONG MiFreeSwapPages
;
85 /* Number of pages that have been allocated for swapping */
86 ULONG MiUsedSwapPages
;
89 * Number of pages that have been reserved for swapping but not yet allocated
91 static ULONG MiReservedSwapPages
;
94 * Ratio between reserved and available swap pages, e.g. setting this to five
95 * forces one swap page to be available for every five swap pages that are
96 * reserved. Setting this to zero turns off commit checking altogether.
98 #define MM_PAGEFILE_COMMIT_RATIO (1)
101 * Number of pages that can be used for potentially swapable memory without
102 * pagefile space being reserved. The intention is that this allows smss
103 * to start up and create page files while ordinarily having a commit
106 #define MM_PAGEFILE_COMMIT_GRACE (256)
108 static PVOID MmCoreDumpPageFrame
= NULL
;
109 static ULONG MmCoreDumpSize
;
110 static DUMP_POINTERS MmCoreDumpPointers
;
111 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
112 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
113 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
115 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
118 * Translate between a swap entry and a file and offset pair.
120 #define FILE_FROM_ENTRY(i) ((i) >> 24)
121 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
122 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
124 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
126 /* FUNCTIONS *****************************************************************/
130 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
134 /* Loop through all the paging files */
135 for (i
= 0; i
< MiPagingFileCount
; i
++)
137 /* Check if this is one of them */
138 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
147 MmShowOutOfSpaceMessagePagingFile(VOID
)
149 if (!MmSwapSpaceMessage
)
151 DPRINT1("MM: Out of swap space.\n");
152 MmSwapSpaceMessage
= TRUE
;
157 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
159 /* Simple binary search */
160 ULONG first
, last
, mid
;
162 last
= RetrievalPointers
->ExtentCount
- 1;
163 while (first
<= last
)
165 mid
= (last
- first
) / 2 + first
;
166 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
170 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
175 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
177 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
185 if (mid
== RetrievalPointers
->ExtentCount
- 1)
189 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
191 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
198 #if defined(__GNUC__)
200 return (LARGE_INTEGER
)0LL;
204 const LARGE_INTEGER dummy
=
215 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
218 LARGE_INTEGER file_offset
;
219 IO_STATUS_BLOCK Iosb
;
222 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
223 PMDL Mdl
= (PMDL
)MdlBase
;
225 DPRINT("MmWriteToSwapPage\n");
230 return(STATUS_UNSUCCESSFUL
);
233 i
= FILE_FROM_ENTRY(SwapEntry
);
234 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
236 if (i
>= MAX_PAGING_FILES
)
238 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
241 if (PagingFileList
[i
]->FileObject
== NULL
||
242 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
244 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
248 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
249 MmBuildMdlFromPages(Mdl
, &Page
);
251 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
252 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
254 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
255 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
260 if (Status
== STATUS_PENDING
)
262 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
263 Status
= Iosb
.Status
;
265 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
271 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
274 LARGE_INTEGER file_offset
;
275 IO_STATUS_BLOCK Iosb
;
278 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
279 PMDL Mdl
= (PMDL
)MdlBase
;
281 DPRINT("MmReadFromSwapPage\n");
286 return(STATUS_UNSUCCESSFUL
);
289 i
= FILE_FROM_ENTRY(SwapEntry
);
290 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
292 if (i
>= MAX_PAGING_FILES
)
294 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
297 if (PagingFileList
[i
]->FileObject
== NULL
||
298 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
300 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
304 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
305 MmBuildMdlFromPages(Mdl
, &Page
);
307 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
308 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
310 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
311 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
316 if (Status
== STATUS_PENDING
)
318 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
319 Status
= Iosb
.Status
;
321 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
325 extern BOOLEAN PagingReady
;
330 MmInitPagingFile(VOID
)
334 KeInitializeSpinLock(&PagingFileListLock
);
338 MiReservedSwapPages
= 0;
340 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
342 PagingFileList
[i
] = NULL
;
344 MiPagingFileCount
= 0;
347 * Initialize the crash dump support.
349 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
351 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
352 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
354 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
358 MmCoreDumpSize
= 1024 * 1024;
365 MmReserveSwapPages(ULONG Nr
)
368 ULONG MiAvailSwapPages
;
372 DPRINT1("PAGING USED TOO SOON!!!\n");
375 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
377 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
378 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
379 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
381 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
384 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
390 MmDereserveSwapPages(ULONG Nr
)
396 DPRINT1("PAGING USED TOO SOON!!!\n");
399 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
400 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
401 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
405 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
412 DPRINT1("PAGING USED TOO SOON!!!\n");
415 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
417 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
419 for (j
= 0; j
< 32; j
++)
421 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
423 PagingFile
->AllocMap
[i
] |= (1 << j
);
424 PagingFile
->UsedPages
++;
425 PagingFile
->FreePages
--;
426 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
427 return((i
* 32) + j
);
432 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
438 MmFreeSwapPage(SWAPENTRY Entry
)
446 DPRINT1("PAGING USED TOO SOON!!!\n");
449 i
= FILE_FROM_ENTRY(Entry
);
450 off
= OFFSET_FROM_ENTRY(Entry
);
452 if (i
>= MAX_PAGING_FILES
)
454 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
458 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
459 if (PagingFileList
[i
] == NULL
)
463 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
465 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
467 PagingFileList
[i
]->FreePages
++;
468 PagingFileList
[i
]->UsedPages
--;
473 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
474 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
479 MmIsAvailableSwapPage(VOID
)
481 return(MiFreeSwapPages
> 0);
486 MmAllocSwapPage(VOID
)
495 DPRINT1("PAGING USED TOO SOON!!!\n");
498 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
500 if (MiFreeSwapPages
== 0)
502 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
506 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
508 if (PagingFileList
[i
] != NULL
&&
509 PagingFileList
[i
]->FreePages
>= 1)
511 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
512 if (off
== 0xFFFFFFFF)
515 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
516 return(STATUS_UNSUCCESSFUL
);
520 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
522 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
527 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
532 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
533 MmAllocRetrievelDescriptorList(ULONG Pairs
)
536 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
538 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
539 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
542 RtlZeroMemory(RetDescList
, Size
);
549 MmDumpToPagingFile(ULONG BugCode
,
550 ULONG BugCodeParameter1
,
551 ULONG BugCodeParameter2
,
552 ULONG BugCodeParameter3
,
553 ULONG BugCodeParameter4
,
554 PKTRAP_FRAME TrapFrame
)
556 PMM_CORE_DUMP_HEADER Headers
;
558 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
559 PMDL Mdl
= (PMDL
)MdlBase
;
560 PETHREAD Thread
= PsGetCurrentThread();
563 LONGLONG NextOffset
= 0;
565 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
566 LARGE_INTEGER DiskOffset
;
568 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
570 return(STATUS_UNSUCCESSFUL
);
573 DbgPrint("\nMM: Dumping core: ");
575 /* Prepare the dump headers. */
576 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
577 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
578 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
579 Headers
->Type
= MmCoreDumpType
;
580 if (TrapFrame
!= NULL
)
582 if (!(TrapFrame
->EFlags
& (1 << 17)))
584 memcpy(&Headers
->TrapFrame
, TrapFrame
,
585 sizeof(KTRAP_FRAME
) - (4 * sizeof(ULONG
)));
589 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
592 Headers
->BugCheckCode
= BugCode
;
593 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
594 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
595 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
596 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
597 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
598 Headers
->FaultingStackSize
=
599 StackSize
= (ULONG_PTR
)Thread
->Tcb
.StackBase
- (ULONG_PTR
)Thread
->Tcb
.StackLimit
;
600 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
602 /* Initialize the dump device. */
603 Status
= MmCoreDumpFunctions
->DumpInit();
604 if (!NT_SUCCESS(Status
))
606 DPRINT1("MM: Failed to initialize core dump device.\n");
610 /* Initialize the MDL. */
611 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
612 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
613 MdlMap
= (PULONG
)(Mdl
+ 1);
616 /* Initialize the retrieval offsets. */
617 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
619 /* Dump the header. */
620 MdlMap
[0] = (ULONG
)(MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
);
621 #if defined(__GNUC__)
623 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
627 const LARGE_INTEGER dummy
=
631 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
634 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
635 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
636 if (!NT_SUCCESS(Status
))
638 DPRINT1("MM: Failed to write core dump header\n.");
641 NextOffset
+= PAGE_SIZE
;
646 /* Write out the contents of physical memory. */
647 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
649 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
652 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
656 #if defined(__GNUC__)
658 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
659 (LARGE_INTEGER
)NextOffset
);
664 dummy
.QuadPart
= NextOffset
;
665 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
668 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
669 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
670 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
671 if (!NT_SUCCESS(Status
))
673 DPRINT1("MM: Failed to write page to core dump.\n");
676 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
678 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
680 NextOffset
+= PAGE_SIZE
;
685 MmCoreDumpFunctions
->DumpFinish();
686 return(STATUS_SUCCESS
);
690 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
692 PFILE_OBJECT PageFile
;
693 PDEVICE_OBJECT PageFileDevice
;
697 IO_STATUS_BLOCK Iosb
;
698 UNICODE_STRING DiskDumpName
= RTL_CONSTANT_STRING(L
"DiskDump");
699 ANSI_STRING ProcName
;
700 PIO_STACK_LOCATION StackPtr
;
701 PLDR_DATA_TABLE_ENTRY ModuleObject
= NULL
;
703 Status
= ZwFsControlFile(PageFileHandle
,
708 FSCTL_ROS_QUERY_LCN_MAPPING
,
711 &MmCoreDumpLcnMapping
,
712 sizeof(ROS_QUERY_LCN_MAPPING
));
713 if (!NT_SUCCESS(Status
) ||
714 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
719 /* Get the underlying storage device. */
721 ObReferenceObjectByHandle(PageFileHandle
,
727 if (!NT_SUCCESS(Status
))
732 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
734 /* Get the dump pointers. */
735 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
736 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
741 sizeof(MmCoreDumpPointers
),
747 ObDereferenceObject(PageFile
);
748 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
751 StackPtr
= IoGetNextIrpStackLocation(Irp
);
752 StackPtr
->FileObject
= PageFile
;
753 StackPtr
->DeviceObject
= PageFileDevice
;
754 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
755 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
757 Status
= IoCallDriver(PageFileDevice
,Irp
);
758 if (Status
== STATUS_PENDING
)
760 Status
= KeWaitForSingleObject(&Event
,
766 if (Status
!= STATUS_SUCCESS
||
767 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
769 ObDereferenceObject(PageFile
);
773 /* Load the diskdump driver. */
774 Status
= MmLoadSystemImage(&DiskDumpName
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, NULL
);
775 if (ModuleObject
== NULL
)
777 return(STATUS_OBJECT_NAME_NOT_FOUND
);
779 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
780 MmCoreDumpFunctions
= MiFindExportedRoutineByName(ModuleObject
->DllBase
,
782 if (!NT_SUCCESS(Status
))
784 ObDereferenceObject(PageFile
);
788 /* Prepare for disk dumping. */
789 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
790 &MmCoreDumpPointers
);
791 if (!NT_SUCCESS(Status
))
793 ObDereferenceObject(PageFile
);
797 MmCoreDumpPageFile
= PageFileNum
;
798 ObDereferenceObject(PageFile
);
799 return(STATUS_SUCCESS
);
803 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
804 IN PLARGE_INTEGER InitialSize
,
805 IN PLARGE_INTEGER MaximumSize
,
808 NTSTATUS Status
= STATUS_SUCCESS
;
809 OBJECT_ATTRIBUTES ObjectAttributes
;
811 IO_STATUS_BLOCK IoStatus
;
812 PFILE_OBJECT FileObject
;
813 PPAGINGFILE PagingFile
;
816 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
817 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
818 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
820 ULONG BytesPerAllocationUnit
;
823 LARGE_INTEGER MaxVcn
;
826 KPROCESSOR_MODE PreviousMode
;
827 UNICODE_STRING CapturedFileName
;
828 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
830 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
831 FileName
, InitialSize
->QuadPart
);
833 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
835 return(STATUS_TOO_MANY_PAGING_FILES
);
838 PreviousMode
= ExGetPreviousMode();
840 if (PreviousMode
!= KernelMode
)
844 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
845 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
849 Status
= _SEH_GetExceptionCode();
853 if (!NT_SUCCESS(Status
))
860 SafeInitialSize
= *InitialSize
;
861 SafeMaximumSize
= *MaximumSize
;
864 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
865 smaller than the maximum */
866 if (0 != SafeInitialSize
.u
.HighPart
)
868 return STATUS_INVALID_PARAMETER_2
;
870 if (0 != SafeMaximumSize
.u
.HighPart
)
872 return STATUS_INVALID_PARAMETER_3
;
874 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
876 return STATUS_INVALID_PARAMETER_MIX
;
879 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
882 if (!NT_SUCCESS(Status
))
887 InitializeObjectAttributes(&ObjectAttributes
,
893 Status
= IoCreateFile(&FileHandle
,
901 FILE_SYNCHRONOUS_IO_NONALERT
,
906 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
908 ReleaseCapturedUnicodeString(&CapturedFileName
,
910 if (!NT_SUCCESS(Status
))
915 Status
= ZwQueryVolumeInformationFile(FileHandle
,
918 sizeof(FILE_FS_SIZE_INFORMATION
),
919 FileFsSizeInformation
);
920 if (!NT_SUCCESS(Status
))
926 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
927 FsSizeInformation
.BytesPerSector
;
928 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
929 * a problem if the paging file is fragmented. Suppose the first cluster
930 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
931 * paging file but of another file. We can't write a complete page (4096
932 * bytes) to the physical location of cluster 3042 then. */
933 if (BytesPerAllocationUnit
% PAGE_SIZE
)
935 DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
936 BytesPerAllocationUnit
, PAGE_SIZE
);
938 return STATUS_UNSUCCESSFUL
;
941 Status
= ZwSetInformationFile(FileHandle
,
944 sizeof(LARGE_INTEGER
),
945 FileAllocationInformation
);
946 if (!NT_SUCCESS(Status
))
952 Status
= ObReferenceObjectByHandle(FileHandle
,
958 if (!NT_SUCCESS(Status
))
964 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
966 if (CurrentRetDescList
== NULL
)
968 ObDereferenceObject(FileObject
);
970 return(STATUS_NO_MEMORY
);
973 #if defined(__GNUC__)
981 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
984 Status
= ZwFsControlFile(FileHandle
,
989 FSCTL_GET_RETRIEVAL_POINTERS
,
991 sizeof(LARGE_INTEGER
),
992 &CurrentRetDescList
->RetrievalPointers
,
993 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
994 if (!NT_SUCCESS(Status
))
998 CurrentRetDescList
= RetDescList
;
999 RetDescList
= RetDescList
->Next
;
1000 ExFreePool(CurrentRetDescList
);
1002 ObDereferenceObject(FileObject
);
1003 ZwClose(FileHandle
);
1006 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1007 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
1009 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
1010 if (CurrentRetDescList
->Next
== NULL
)
1014 CurrentRetDescList
= RetDescList
;
1015 RetDescList
= RetDescList
->Next
;
1016 ExFreePool(CurrentRetDescList
);
1018 ObDereferenceObject(FileObject
);
1019 ZwClose(FileHandle
);
1020 return(STATUS_NO_MEMORY
);
1022 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
1023 CurrentRetDescList
= CurrentRetDescList
->Next
;
1031 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
1032 if (PagingFile
== NULL
)
1036 CurrentRetDescList
= RetDescList
;
1037 RetDescList
= RetDescList
->Next
;
1038 ExFreePool(CurrentRetDescList
);
1040 ObDereferenceObject(FileObject
);
1041 ZwClose(FileHandle
);
1042 return(STATUS_NO_MEMORY
);
1045 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
1047 PagingFile
->FileObject
= FileObject
;
1048 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
1049 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
1050 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
1051 PagingFile
->UsedPages
= 0;
1052 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
1054 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
1055 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
1056 AllocMapSize
* sizeof(ULONG
));
1057 PagingFile
->AllocMapSize
= AllocMapSize
;
1059 if (PagingFile
->AllocMap
== NULL
)
1063 CurrentRetDescList
= RetDescList
;
1064 RetDescList
= RetDescList
->Next
;
1065 ExFreePool(CurrentRetDescList
);
1067 ExFreePool(PagingFile
);
1068 ObDereferenceObject(FileObject
);
1069 ZwClose(FileHandle
);
1070 return(STATUS_NO_MEMORY
);
1072 DPRINT("ExtentCount: %d\n", ExtentCount
);
1073 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
1074 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
1075 if (PagingFile
->RetrievalPointers
== NULL
)
1079 CurrentRetDescList
= RetDescList
;
1080 RetDescList
= RetDescList
->Next
;
1081 ExFreePool(CurrentRetDescList
);
1083 ExFreePool(PagingFile
->AllocMap
);
1084 ExFreePool(PagingFile
);
1085 ObDereferenceObject(FileObject
);
1086 ZwClose(FileHandle
);
1087 return(STATUS_NO_MEMORY
);
1090 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
1091 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
1094 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
1095 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
1096 CurrentRetDescList
= RetDescList
;
1097 while (CurrentRetDescList
)
1099 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
1100 CurrentRetDescList
->RetrievalPointers
.Extents
,
1101 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
1102 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1103 RetDescList
= CurrentRetDescList
;
1104 CurrentRetDescList
= CurrentRetDescList
->Next
;
1105 ExFreePool(RetDescList
);
1108 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
1109 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
1111 ExFreePool(PagingFile
->RetrievalPointers
);
1112 ExFreePool(PagingFile
->AllocMap
);
1113 ExFreePool(PagingFile
);
1114 ObDereferenceObject(FileObject
);
1115 ZwClose(FileHandle
);
1116 return(STATUS_UNSUCCESSFUL
);
1120 * Change the entries from lcn's to volume offset's.
1122 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
1123 for (i
= 0; i
< ExtentCount
; i
++)
1125 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
1126 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
1129 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1130 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1132 if (PagingFileList
[i
] == NULL
)
1134 PagingFileList
[i
] = PagingFile
;
1138 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1139 MiPagingFileCount
++;
1140 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1142 /* Check whether this pagefile can be a crash dump target. */
1143 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1144 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1145 MmCoreDumpPageFile
== 0xFFFFFFFF)
1147 MmInitializeCrashDump(FileHandle
, i
);
1149 ZwClose(FileHandle
);
1151 MmSwapSpaceMessage
= FALSE
;
1153 return(STATUS_SUCCESS
);