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)
39 /* TYPES *********************************************************************/
41 typedef struct _PAGINGFILE
43 LIST_ENTRY PagingFileListEntry
;
44 PFILE_OBJECT FileObject
;
45 LARGE_INTEGER MaximumSize
;
46 LARGE_INTEGER CurrentSize
;
50 KSPIN_LOCK AllocMapLock
;
52 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
54 PAGINGFILE
, *PPAGINGFILE
;
56 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
58 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
59 RETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
61 RETRIEVEL_DESCRIPTOR_LIST
, *PRETRIEVEL_DESCRIPTOR_LIST
;
63 /* GLOBALS *******************************************************************/
65 #define PAIRS_PER_RUN (1024)
67 #define MAX_PAGING_FILES (32)
69 /* List of paging files, both used and free */
70 static PPAGINGFILE PagingFileList
[MAX_PAGING_FILES
];
72 /* Lock for examining the list of paging files */
73 static KSPIN_LOCK PagingFileListLock
;
75 /* Number of paging files */
76 static ULONG MiPagingFileCount
;
78 /* Number of pages that are available for swapping */
79 ULONG MiFreeSwapPages
;
81 /* Number of pages that have been allocated for swapping */
82 ULONG MiUsedSwapPages
;
85 * Number of pages that have been reserved for swapping but not yet allocated
87 static ULONG MiReservedSwapPages
;
90 * Ratio between reserved and available swap pages, e.g. setting this to five
91 * forces one swap page to be available for every five swap pages that are
92 * reserved. Setting this to zero turns off commit checking altogether.
94 #define MM_PAGEFILE_COMMIT_RATIO (1)
97 * Number of pages that can be used for potentially swapable memory without
98 * pagefile space being reserved. The intention is that this allows smss
99 * to start up and create page files while ordinarily having a commit
102 #define MM_PAGEFILE_COMMIT_GRACE (256)
104 static PVOID MmCoreDumpPageFrame
= NULL
;
105 static ULONG MmCoreDumpSize
;
106 static DUMP_POINTERS MmCoreDumpPointers
;
107 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions
;
108 static ULONG MmCoreDumpPageFile
= 0xFFFFFFFF;
109 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping
;
111 ULONG MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
114 * Translate between a swap entry and a file and offset pair.
116 #define FILE_FROM_ENTRY(i) ((i) >> 24)
117 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
118 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
120 static BOOLEAN MmSwapSpaceMessage
= FALSE
;
122 /* FUNCTIONS *****************************************************************/
126 MmIsFileAPagingFile(PFILE_OBJECT FileObject
)
130 /* Loop through all the paging files */
131 for (i
= 0; i
< MiPagingFileCount
; i
++)
133 /* Check if this is one of them */
134 if (PagingFileList
[i
]->FileObject
== FileObject
) return TRUE
;
143 MmShowOutOfSpaceMessagePagingFile(VOID
)
145 if (!MmSwapSpaceMessage
)
147 DPRINT1("MM: Out of swap space.\n");
148 MmSwapSpaceMessage
= TRUE
;
153 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
, LARGE_INTEGER Offset
)
155 /* Simple binary search */
156 ULONG first
, last
, mid
;
158 last
= RetrievalPointers
->ExtentCount
- 1;
159 while (first
<= last
)
161 mid
= (last
- first
) / 2 + first
;
162 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
)
166 Offset
.QuadPart
+= RetrievalPointers
->Extents
[0].Lcn
.QuadPart
- RetrievalPointers
->StartingVcn
.QuadPart
;
171 if (Offset
.QuadPart
>= RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
)
173 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
-1].NextVcn
.QuadPart
;
181 if (mid
== RetrievalPointers
->ExtentCount
- 1)
185 if (Offset
.QuadPart
< RetrievalPointers
->Extents
[mid
+1].NextVcn
.QuadPart
)
187 Offset
.QuadPart
+= RetrievalPointers
->Extents
[mid
+1].Lcn
.QuadPart
- RetrievalPointers
->Extents
[mid
].NextVcn
.QuadPart
;
194 #if defined(__GNUC__)
196 return (LARGE_INTEGER
)0LL;
200 const LARGE_INTEGER dummy
=
211 MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
214 LARGE_INTEGER file_offset
;
215 IO_STATUS_BLOCK Iosb
;
218 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
219 PMDL Mdl
= (PMDL
)MdlBase
;
221 DPRINT("MmWriteToSwapPage\n");
226 return(STATUS_UNSUCCESSFUL
);
229 i
= FILE_FROM_ENTRY(SwapEntry
);
230 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
232 if (i
>= MAX_PAGING_FILES
)
234 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
237 if (PagingFileList
[i
]->FileObject
== NULL
||
238 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
240 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
244 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
245 MmBuildMdlFromPages(Mdl
, &Page
);
247 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
248 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
250 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
251 Status
= IoSynchronousPageWrite(PagingFileList
[i
]->FileObject
,
256 if (Status
== STATUS_PENDING
)
258 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
259 Status
= Iosb
.Status
;
261 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
267 MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
270 LARGE_INTEGER file_offset
;
271 IO_STATUS_BLOCK Iosb
;
274 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
275 PMDL Mdl
= (PMDL
)MdlBase
;
277 DPRINT("MmReadFromSwapPage\n");
282 return(STATUS_UNSUCCESSFUL
);
285 i
= FILE_FROM_ENTRY(SwapEntry
);
286 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
288 if (i
>= MAX_PAGING_FILES
)
290 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
293 if (PagingFileList
[i
]->FileObject
== NULL
||
294 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
296 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
300 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
301 MmBuildMdlFromPages(Mdl
, &Page
);
303 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
304 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
306 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
307 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
312 if (Status
== STATUS_PENDING
)
314 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
315 Status
= Iosb
.Status
;
317 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
321 extern BOOLEAN PagingReady
;
326 MmInitPagingFile(VOID
)
330 KeInitializeSpinLock(&PagingFileListLock
);
334 MiReservedSwapPages
= 0;
336 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
338 PagingFileList
[i
] = NULL
;
340 MiPagingFileCount
= 0;
343 * Initialize the crash dump support.
345 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
347 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
348 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
350 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
354 MmCoreDumpSize
= 1024 * 1024;
361 MmReserveSwapPages(ULONG Nr
)
364 ULONG MiAvailSwapPages
;
368 DPRINT1("PAGING USED TOO SOON!!!\n");
371 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
373 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
374 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
375 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
377 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
380 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
386 MmDereserveSwapPages(ULONG Nr
)
392 DPRINT1("PAGING USED TOO SOON!!!\n");
395 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
396 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
397 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
401 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
408 DPRINT1("PAGING USED TOO SOON!!!\n");
411 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
413 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
415 for (j
= 0; j
< 32; j
++)
417 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
419 PagingFile
->AllocMap
[i
] |= (1 << j
);
420 PagingFile
->UsedPages
++;
421 PagingFile
->FreePages
--;
422 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
423 return((i
* 32) + j
);
428 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
434 MmFreeSwapPage(SWAPENTRY Entry
)
442 DPRINT1("PAGING USED TOO SOON!!!\n");
445 i
= FILE_FROM_ENTRY(Entry
);
446 off
= OFFSET_FROM_ENTRY(Entry
);
448 if (i
>= MAX_PAGING_FILES
)
450 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
454 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
455 if (PagingFileList
[i
] == NULL
)
459 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
461 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
463 PagingFileList
[i
]->FreePages
++;
464 PagingFileList
[i
]->UsedPages
--;
469 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
470 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
475 MmIsAvailableSwapPage(VOID
)
477 return(MiFreeSwapPages
> 0);
482 MmAllocSwapPage(VOID
)
491 DPRINT1("PAGING USED TOO SOON!!!\n");
494 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
496 if (MiFreeSwapPages
== 0)
498 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
502 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
504 if (PagingFileList
[i
] != NULL
&&
505 PagingFileList
[i
]->FreePages
>= 1)
507 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
508 if (off
== 0xFFFFFFFF)
511 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
512 return(STATUS_UNSUCCESSFUL
);
516 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
518 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
523 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
528 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
529 MmAllocRetrievelDescriptorList(ULONG Pairs
)
532 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
534 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* 2 * sizeof(LARGE_INTEGER
);
535 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
538 RtlZeroMemory(RetDescList
, Size
);
545 MmDumpToPagingFile(ULONG BugCode
,
546 ULONG BugCodeParameter1
,
547 ULONG BugCodeParameter2
,
548 ULONG BugCodeParameter3
,
549 ULONG BugCodeParameter4
,
550 PKTRAP_FRAME TrapFrame
)
552 PMM_CORE_DUMP_HEADER Headers
;
554 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
555 PMDL Mdl
= (PMDL
)MdlBase
;
556 PETHREAD Thread
= PsGetCurrentThread();
559 LONGLONG NextOffset
= 0;
561 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers
;
562 LARGE_INTEGER DiskOffset
;
564 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
566 return(STATUS_UNSUCCESSFUL
);
569 DbgPrint("\nMM: Dumping core: ");
571 /* Prepare the dump headers. */
572 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
573 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
574 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
575 Headers
->Type
= MmCoreDumpType
;
576 if (TrapFrame
!= NULL
)
578 if (!(TrapFrame
->EFlags
& (1 << 17)))
580 memcpy(&Headers
->TrapFrame
, TrapFrame
,
581 sizeof(KTRAP_FRAME
) - (4 * sizeof(ULONG
)));
585 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
588 Headers
->BugCheckCode
= BugCode
;
589 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
590 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
591 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
592 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
593 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
594 Headers
->FaultingStackSize
=
595 StackSize
= (ULONG_PTR
)Thread
->Tcb
.StackBase
- (ULONG_PTR
)Thread
->Tcb
.StackLimit
;
596 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
598 /* Initialize the dump device. */
599 Status
= MmCoreDumpFunctions
->DumpInit();
600 if (!NT_SUCCESS(Status
))
602 DPRINT1("MM: Failed to initialize core dump device.\n");
606 /* Initialize the MDL. */
607 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
608 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
609 MdlMap
= (PULONG
)(Mdl
+ 1);
612 /* Initialize the retrieval offsets. */
613 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
615 /* Dump the header. */
616 MdlMap
[0] = (ULONG
)(MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
);
617 #if defined(__GNUC__)
619 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
623 const LARGE_INTEGER dummy
=
627 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
630 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
631 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
632 if (!NT_SUCCESS(Status
))
634 DPRINT1("MM: Failed to write core dump header\n.");
637 NextOffset
+= PAGE_SIZE
;
642 /* Write out the contents of physical memory. */
643 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
645 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
648 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
652 #if defined(__GNUC__)
654 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
655 (LARGE_INTEGER
)NextOffset
);
660 dummy
.QuadPart
= NextOffset
;
661 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
664 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
665 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
666 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
667 if (!NT_SUCCESS(Status
))
669 DPRINT1("MM: Failed to write page to core dump.\n");
672 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
674 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
676 NextOffset
+= PAGE_SIZE
;
681 MmCoreDumpFunctions
->DumpFinish();
682 return(STATUS_SUCCESS
);
686 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
688 PFILE_OBJECT PageFile
;
689 PDEVICE_OBJECT PageFileDevice
;
693 IO_STATUS_BLOCK Iosb
;
694 UNICODE_STRING DiskDumpName
= RTL_CONSTANT_STRING(L
"DiskDump");
695 ANSI_STRING ProcName
;
696 PIO_STACK_LOCATION StackPtr
;
697 PLDR_DATA_TABLE_ENTRY ModuleObject
;
699 Status
= ZwFsControlFile(PageFileHandle
,
704 FSCTL_ROS_QUERY_LCN_MAPPING
,
707 &MmCoreDumpLcnMapping
,
708 sizeof(ROS_QUERY_LCN_MAPPING
));
709 if (!NT_SUCCESS(Status
) ||
710 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
715 /* Get the underlying storage device. */
717 ObReferenceObjectByHandle(PageFileHandle
,
723 if (!NT_SUCCESS(Status
))
728 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
730 /* Get the dump pointers. */
731 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
732 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
737 sizeof(MmCoreDumpPointers
),
743 ObDereferenceObject(PageFile
);
744 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
747 StackPtr
= IoGetNextIrpStackLocation(Irp
);
748 StackPtr
->FileObject
= PageFile
;
749 StackPtr
->DeviceObject
= PageFileDevice
;
750 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
751 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
753 Status
= IoCallDriver(PageFileDevice
,Irp
);
754 if (Status
== STATUS_PENDING
)
756 Status
= KeWaitForSingleObject(&Event
,
762 if (Status
!= STATUS_SUCCESS
||
763 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
765 ObDereferenceObject(PageFile
);
769 /* Load the diskdump driver. */
770 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
771 if (ModuleObject
== NULL
)
773 return(STATUS_OBJECT_NAME_NOT_FOUND
);
775 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
776 Status
= LdrGetProcedureAddress(ModuleObject
->DllBase
,
779 (PVOID
*)&MmCoreDumpFunctions
);
780 if (!NT_SUCCESS(Status
))
782 ObDereferenceObject(PageFile
);
786 /* Prepare for disk dumping. */
787 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
788 &MmCoreDumpPointers
);
789 if (!NT_SUCCESS(Status
))
791 ObDereferenceObject(PageFile
);
795 MmCoreDumpPageFile
= PageFileNum
;
796 ObDereferenceObject(PageFile
);
797 return(STATUS_SUCCESS
);
801 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
802 IN PLARGE_INTEGER InitialSize
,
803 IN PLARGE_INTEGER MaximumSize
,
806 NTSTATUS Status
= STATUS_SUCCESS
;
807 OBJECT_ATTRIBUTES ObjectAttributes
;
809 IO_STATUS_BLOCK IoStatus
;
810 PFILE_OBJECT FileObject
;
811 PPAGINGFILE PagingFile
;
814 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
815 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
816 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
818 ULONG BytesPerAllocationUnit
;
821 LARGE_INTEGER MaxVcn
;
824 KPROCESSOR_MODE PreviousMode
;
825 UNICODE_STRING CapturedFileName
;
826 LARGE_INTEGER SafeInitialSize
, SafeMaximumSize
;
828 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
829 FileName
, InitialSize
->QuadPart
);
831 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
833 return(STATUS_TOO_MANY_PAGING_FILES
);
836 PreviousMode
= ExGetPreviousMode();
838 if (PreviousMode
!= KernelMode
)
842 SafeInitialSize
= ProbeForReadLargeInteger(InitialSize
);
843 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
847 Status
= _SEH_GetExceptionCode();
851 if (!NT_SUCCESS(Status
))
858 SafeInitialSize
= *InitialSize
;
859 SafeMaximumSize
= *MaximumSize
;
862 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
863 smaller than the maximum */
864 if (0 != SafeInitialSize
.u
.HighPart
)
866 return STATUS_INVALID_PARAMETER_2
;
868 if (0 != SafeMaximumSize
.u
.HighPart
)
870 return STATUS_INVALID_PARAMETER_3
;
872 if (SafeMaximumSize
.u
.LowPart
< SafeInitialSize
.u
.LowPart
)
874 return STATUS_INVALID_PARAMETER_MIX
;
877 Status
= ProbeAndCaptureUnicodeString(&CapturedFileName
,
880 if (!NT_SUCCESS(Status
))
885 InitializeObjectAttributes(&ObjectAttributes
,
891 Status
= IoCreateFile(&FileHandle
,
899 FILE_SYNCHRONOUS_IO_NONALERT
,
904 SL_OPEN_PAGING_FILE
| IO_NO_PARAMETER_CHECKING
);
906 ReleaseCapturedUnicodeString(&CapturedFileName
,
908 if (!NT_SUCCESS(Status
))
913 Status
= ZwQueryVolumeInformationFile(FileHandle
,
916 sizeof(FILE_FS_SIZE_INFORMATION
),
917 FileFsSizeInformation
);
918 if (!NT_SUCCESS(Status
))
924 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
*
925 FsSizeInformation
.BytesPerSector
;
926 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
927 * a problem if the paging file is fragmented. Suppose the first cluster
928 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
929 * paging file but of another file. We can't write a complete page (4096
930 * bytes) to the physical location of cluster 3042 then. */
931 if (BytesPerAllocationUnit
% PAGE_SIZE
)
933 DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
934 BytesPerAllocationUnit
, PAGE_SIZE
);
936 return STATUS_UNSUCCESSFUL
;
939 Status
= ZwSetInformationFile(FileHandle
,
942 sizeof(LARGE_INTEGER
),
943 FileAllocationInformation
);
944 if (!NT_SUCCESS(Status
))
950 Status
= ObReferenceObjectByHandle(FileHandle
,
956 if (!NT_SUCCESS(Status
))
962 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
964 if (CurrentRetDescList
== NULL
)
966 ObDereferenceObject(FileObject
);
968 return(STATUS_NO_MEMORY
);
971 #if defined(__GNUC__)
979 MaxVcn
.QuadPart
= (SafeInitialSize
.QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
;
982 Status
= ZwFsControlFile(FileHandle
,
987 FSCTL_GET_RETRIEVAL_POINTERS
,
989 sizeof(LARGE_INTEGER
),
990 &CurrentRetDescList
->RetrievalPointers
,
991 sizeof(RETRIEVAL_POINTERS_BUFFER
) + PAIRS_PER_RUN
* 2 * sizeof(LARGE_INTEGER
));
992 if (!NT_SUCCESS(Status
))
996 CurrentRetDescList
= RetDescList
;
997 RetDescList
= RetDescList
->Next
;
998 ExFreePool(CurrentRetDescList
);
1000 ObDereferenceObject(FileObject
);
1001 ZwClose(FileHandle
);
1004 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1005 if (CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
.QuadPart
< MaxVcn
.QuadPart
)
1007 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
1008 if (CurrentRetDescList
->Next
== NULL
)
1012 CurrentRetDescList
= RetDescList
;
1013 RetDescList
= RetDescList
->Next
;
1014 ExFreePool(CurrentRetDescList
);
1016 ObDereferenceObject(FileObject
);
1017 ZwClose(FileHandle
);
1018 return(STATUS_NO_MEMORY
);
1020 Vcn
= CurrentRetDescList
->RetrievalPointers
.Extents
[CurrentRetDescList
->RetrievalPointers
.ExtentCount
-1].NextVcn
;
1021 CurrentRetDescList
= CurrentRetDescList
->Next
;
1029 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
1030 if (PagingFile
== NULL
)
1034 CurrentRetDescList
= RetDescList
;
1035 RetDescList
= RetDescList
->Next
;
1036 ExFreePool(CurrentRetDescList
);
1038 ObDereferenceObject(FileObject
);
1039 ZwClose(FileHandle
);
1040 return(STATUS_NO_MEMORY
);
1043 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
1045 PagingFile
->FileObject
= FileObject
;
1046 PagingFile
->MaximumSize
.QuadPart
= SafeMaximumSize
.QuadPart
;
1047 PagingFile
->CurrentSize
.QuadPart
= SafeInitialSize
.QuadPart
;
1048 PagingFile
->FreePages
= (ULONG
)(SafeInitialSize
.QuadPart
/ PAGE_SIZE
);
1049 PagingFile
->UsedPages
= 0;
1050 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
1052 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
1053 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
1054 AllocMapSize
* sizeof(ULONG
));
1055 PagingFile
->AllocMapSize
= AllocMapSize
;
1057 if (PagingFile
->AllocMap
== NULL
)
1061 CurrentRetDescList
= RetDescList
;
1062 RetDescList
= RetDescList
->Next
;
1063 ExFreePool(CurrentRetDescList
);
1065 ExFreePool(PagingFile
);
1066 ObDereferenceObject(FileObject
);
1067 ZwClose(FileHandle
);
1068 return(STATUS_NO_MEMORY
);
1070 DPRINT("ExtentCount: %d\n", ExtentCount
);
1071 Size
= sizeof(RETRIEVAL_POINTERS_BUFFER
) + ExtentCount
* 2 * sizeof(LARGE_INTEGER
);
1072 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
1073 if (PagingFile
->RetrievalPointers
== NULL
)
1077 CurrentRetDescList
= RetDescList
;
1078 RetDescList
= RetDescList
->Next
;
1079 ExFreePool(CurrentRetDescList
);
1081 ExFreePool(PagingFile
->AllocMap
);
1082 ExFreePool(PagingFile
);
1083 ObDereferenceObject(FileObject
);
1084 ZwClose(FileHandle
);
1085 return(STATUS_NO_MEMORY
);
1088 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
1089 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
1092 PagingFile
->RetrievalPointers
->ExtentCount
= ExtentCount
;
1093 PagingFile
->RetrievalPointers
->StartingVcn
= RetDescList
->RetrievalPointers
.StartingVcn
;
1094 CurrentRetDescList
= RetDescList
;
1095 while (CurrentRetDescList
)
1097 memcpy(&PagingFile
->RetrievalPointers
->Extents
[Count
],
1098 CurrentRetDescList
->RetrievalPointers
.Extents
,
1099 CurrentRetDescList
->RetrievalPointers
.ExtentCount
* 2 * sizeof(LARGE_INTEGER
));
1100 Count
+= CurrentRetDescList
->RetrievalPointers
.ExtentCount
;
1101 RetDescList
= CurrentRetDescList
;
1102 CurrentRetDescList
= CurrentRetDescList
->Next
;
1103 ExFreePool(RetDescList
);
1106 if (PagingFile
->RetrievalPointers
->ExtentCount
!= ExtentCount
||
1107 PagingFile
->RetrievalPointers
->Extents
[ExtentCount
- 1].NextVcn
.QuadPart
!= MaxVcn
.QuadPart
)
1109 ExFreePool(PagingFile
->RetrievalPointers
);
1110 ExFreePool(PagingFile
->AllocMap
);
1111 ExFreePool(PagingFile
);
1112 ObDereferenceObject(FileObject
);
1113 ZwClose(FileHandle
);
1114 return(STATUS_UNSUCCESSFUL
);
1118 * Change the entries from lcn's to volume offset's.
1120 PagingFile
->RetrievalPointers
->StartingVcn
.QuadPart
*= BytesPerAllocationUnit
;
1121 for (i
= 0; i
< ExtentCount
; i
++)
1123 PagingFile
->RetrievalPointers
->Extents
[i
].Lcn
.QuadPart
*= BytesPerAllocationUnit
;
1124 PagingFile
->RetrievalPointers
->Extents
[i
].NextVcn
.QuadPart
*= BytesPerAllocationUnit
;
1127 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1128 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1130 if (PagingFileList
[i
] == NULL
)
1132 PagingFileList
[i
] = PagingFile
;
1136 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1137 MiPagingFileCount
++;
1138 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1140 /* Check whether this pagefile can be a crash dump target. */
1141 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1142 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1143 MmCoreDumpPageFile
== 0xFFFFFFFF)
1145 MmInitializeCrashDump(FileHandle
, i
);
1147 ZwClose(FileHandle
);
1149 MmSwapSpaceMessage
= FALSE
;
1151 return(STATUS_SUCCESS
);