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 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
;
50 PAGINGFILE
, *PPAGINGFILE
;
52 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
54 struct _RETRIEVEL_DESCRIPTOR_LIST
* Next
;
55 GET_RETRIEVAL_DESCRIPTOR 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 *****************************************************************/
121 MmShowOutOfSpaceMessagePagingFile(VOID
)
123 if (!MmSwapSpaceMessage
)
125 DPRINT1("MM: Out of swap space.\n");
126 MmSwapSpaceMessage
= TRUE
;
131 MmGetOffsetPageFile(PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
, LARGE_INTEGER Offset
)
133 /* Simple binary search */
134 ULONG first
, last
, mid
;
136 last
= RetrievalPointers
->NumberOfPairs
- 1;
137 while (first
<= last
)
139 mid
= (last
- first
) / 2 + first
;
140 if ((ULONGLONG
) Offset
.QuadPart
< RetrievalPointers
->Pair
[mid
].Vcn
)
144 Offset
.QuadPart
+= RetrievalPointers
->Pair
[0].Lcn
- RetrievalPointers
->StartVcn
;
149 if ((ULONGLONG
) Offset
.QuadPart
>= RetrievalPointers
->Pair
[mid
-1].Vcn
)
151 Offset
.QuadPart
+= RetrievalPointers
->Pair
[mid
].Lcn
- RetrievalPointers
->Pair
[mid
-1].Vcn
;
159 if (mid
== RetrievalPointers
->NumberOfPairs
- 1)
163 if ((ULONGLONG
) Offset
.QuadPart
< RetrievalPointers
->Pair
[mid
+1].Vcn
)
165 Offset
.QuadPart
+= RetrievalPointers
->Pair
[mid
+1].Lcn
- RetrievalPointers
->Pair
[mid
].Vcn
;
172 #if defined(__GNUC__)
174 return (LARGE_INTEGER
)0LL;
178 const LARGE_INTEGER dummy
=
187 NTSTATUS
MmWriteToSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
190 LARGE_INTEGER file_offset
;
191 IO_STATUS_BLOCK Iosb
;
194 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
195 PMDL Mdl
= (PMDL
)MdlBase
;
197 DPRINT("MmWriteToSwapPage\n");
202 return(STATUS_UNSUCCESSFUL
);
205 i
= FILE_FROM_ENTRY(SwapEntry
);
206 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
208 if (i
>= MAX_PAGING_FILES
)
210 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
213 if (PagingFileList
[i
]->FileObject
== NULL
||
214 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
216 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
220 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
221 MmBuildMdlFromPages(Mdl
, &Page
);
223 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
224 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
226 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
227 Status
= IoPageWrite(PagingFileList
[i
]->FileObject
,
232 if (Status
== STATUS_PENDING
)
234 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
235 Status
= Iosb
.Status
;
237 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
241 NTSTATUS
MmReadFromSwapPage(SWAPENTRY SwapEntry
, PFN_TYPE Page
)
244 LARGE_INTEGER file_offset
;
245 IO_STATUS_BLOCK Iosb
;
248 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
249 PMDL Mdl
= (PMDL
)MdlBase
;
251 DPRINT("MmReadFromSwapPage\n");
256 return(STATUS_UNSUCCESSFUL
);
259 i
= FILE_FROM_ENTRY(SwapEntry
);
260 offset
= OFFSET_FROM_ENTRY(SwapEntry
);
262 if (i
>= MAX_PAGING_FILES
)
264 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry
);
267 if (PagingFileList
[i
]->FileObject
== NULL
||
268 PagingFileList
[i
]->FileObject
->DeviceObject
== NULL
)
270 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry
);
274 MmInitializeMdl(Mdl
, NULL
, PAGE_SIZE
);
275 MmBuildMdlFromPages(Mdl
, &Page
);
277 file_offset
.QuadPart
= offset
* PAGE_SIZE
;
278 file_offset
= MmGetOffsetPageFile(PagingFileList
[i
]->RetrievalPointers
, file_offset
);
280 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
281 Status
= IoPageRead(PagingFileList
[i
]->FileObject
,
286 if (Status
== STATUS_PENDING
)
288 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
289 Status
= Iosb
.Status
;
291 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
296 MmInitPagingFile(VOID
)
300 KeInitializeSpinLock(&PagingFileListLock
);
304 MiReservedSwapPages
= 0;
306 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
308 PagingFileList
[i
] = NULL
;
310 MiPagingFileCount
= 0;
313 * Initialize the crash dump support.
315 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
)
317 MmCoreDumpPageFrame
= MmAllocateSection(PAGE_SIZE
, NULL
);
318 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
320 MmCoreDumpSize
= MmStats
.NrTotalPages
* 4096 + 1024 * 1024;
324 MmCoreDumpSize
= 1024 * 1024;
330 MmReserveSwapPages(ULONG Nr
)
333 ULONG MiAvailSwapPages
;
335 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
337 (MiFreeSwapPages
* MM_PAGEFILE_COMMIT_RATIO
) + MM_PAGEFILE_COMMIT_GRACE
;
338 MiReservedSwapPages
= MiReservedSwapPages
+ Nr
;
339 if (MM_PAGEFILE_COMMIT_RATIO
!= 0 && MiAvailSwapPages
< MiReservedSwapPages
)
341 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
344 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
349 MmDereserveSwapPages(ULONG Nr
)
353 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
354 MiReservedSwapPages
= MiReservedSwapPages
- Nr
;
355 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
359 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile
)
364 KeAcquireSpinLock(&PagingFile
->AllocMapLock
, &oldIrql
);
366 for (i
= 0; i
< PagingFile
->AllocMapSize
; i
++)
368 for (j
= 0; j
< 32; j
++)
370 if (!(PagingFile
->AllocMap
[i
] & (1 << j
)))
372 PagingFile
->AllocMap
[i
] |= (1 << j
);
373 PagingFile
->UsedPages
++;
374 PagingFile
->FreePages
--;
375 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
376 return((i
* 32) + j
);
381 KeReleaseSpinLock(&PagingFile
->AllocMapLock
, oldIrql
);
386 MmFreeSwapPage(SWAPENTRY Entry
)
392 i
= FILE_FROM_ENTRY(Entry
);
393 off
= OFFSET_FROM_ENTRY(Entry
);
395 if (i
>= MAX_PAGING_FILES
)
397 DPRINT1("Bad swap entry 0x%.8X\n", Entry
);
401 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
402 if (PagingFileList
[i
] == NULL
)
406 KeAcquireSpinLockAtDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
408 PagingFileList
[i
]->AllocMap
[off
>> 5] &= (~(1 << (off
% 32)));
410 PagingFileList
[i
]->FreePages
++;
411 PagingFileList
[i
]->UsedPages
--;
416 KeReleaseSpinLockFromDpcLevel(&PagingFileList
[i
]->AllocMapLock
);
417 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
421 MmIsAvailableSwapPage(VOID
)
423 return(MiFreeSwapPages
> 0);
427 MmAllocSwapPage(VOID
)
434 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
436 if (MiFreeSwapPages
== 0)
438 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
442 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
444 if (PagingFileList
[i
] != NULL
&&
445 PagingFileList
[i
]->FreePages
>= 1)
447 off
= MiAllocPageFromPagingFile(PagingFileList
[i
]);
448 if (off
== 0xFFFFFFFF)
451 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
452 return(STATUS_UNSUCCESSFUL
);
456 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
458 entry
= ENTRY_FROM_FILE_OFFSET(i
, off
);
463 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
468 STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
469 MmAllocRetrievelDescriptorList(ULONG Pairs
)
472 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
474 Size
= sizeof(RETRIEVEL_DESCRIPTOR_LIST
) + Pairs
* sizeof(MAPPING_PAIR
);
475 RetDescList
= ExAllocatePool(NonPagedPool
, Size
);
478 RtlZeroMemory(RetDescList
, Size
);
485 MmDumpToPagingFile(ULONG BugCode
,
486 ULONG BugCodeParameter1
,
487 ULONG BugCodeParameter2
,
488 ULONG BugCodeParameter3
,
489 ULONG BugCodeParameter4
,
490 PKTRAP_FRAME TrapFrame
)
492 PMM_CORE_DUMP_HEADER Headers
;
494 UCHAR MdlBase
[sizeof(MDL
) + sizeof(ULONG
)];
495 PMDL Mdl
= (PMDL
)MdlBase
;
496 PETHREAD Thread
= PsGetCurrentThread();
499 LONGLONG NextOffset
= 0;
501 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers
;
502 LARGE_INTEGER DiskOffset
;
504 if (MmCoreDumpPageFile
== 0xFFFFFFFF)
506 return(STATUS_UNSUCCESSFUL
);
509 DbgPrint("\nMM: Dumping core: ");
511 /* Prepare the dump headers. */
512 Headers
= (PMM_CORE_DUMP_HEADER
)MmCoreDumpPageFrame
;
513 Headers
->Magic
= MM_CORE_DUMP_HEADER_MAGIC
;
514 Headers
->Version
= MM_CORE_DUMP_HEADER_VERSION
;
515 Headers
->Type
= MmCoreDumpType
;
516 if (TrapFrame
!= NULL
)
518 if (!(TrapFrame
->Eflags
& (1 << 17)))
520 memcpy(&Headers
->TrapFrame
, TrapFrame
,
521 sizeof(KTRAP_FRAME
) - (4 * sizeof(DWORD
)));
525 memcpy(&Headers
->TrapFrame
, TrapFrame
, sizeof(KTRAP_FRAME
));
528 Headers
->BugCheckCode
= BugCode
;
529 Headers
->BugCheckParameters
[0] = BugCodeParameter1
;
530 Headers
->BugCheckParameters
[1] = BugCodeParameter2
;
531 Headers
->BugCheckParameters
[2] = BugCodeParameter3
;
532 Headers
->BugCheckParameters
[3] = BugCodeParameter4
;
533 Headers
->FaultingStackBase
= (PVOID
)Thread
->Tcb
.StackLimit
;
534 Headers
->FaultingStackSize
=
535 StackSize
= (ULONG_PTR
)(Thread
->Tcb
.StackBase
- Thread
->Tcb
.StackLimit
);
536 Headers
->PhysicalMemorySize
= MmStats
.NrTotalPages
* PAGE_SIZE
;
538 /* Initialize the dump device. */
539 Status
= MmCoreDumpFunctions
->DumpInit();
540 if (!NT_SUCCESS(Status
))
542 DPRINT1("MM: Failed to initialize core dump device.\n");
546 /* Initialize the MDL. */
547 MmInitializeMdl(Mdl
, MmCoreDumpPageFrame
, PAGE_SIZE
);
548 Mdl
->MdlFlags
= MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
|MDL_SOURCE_IS_NONPAGED_POOL
;
549 MdlMap
= (PULONG
)(Mdl
+ 1);
552 /* Initialize the retrieval offsets. */
553 RetrievalPointers
= PagingFileList
[MmCoreDumpPageFile
]->RetrievalPointers
;
555 /* Dump the header. */
556 MdlMap
[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame
).QuadPart
>> PAGE_SHIFT
;
557 #if defined(__GNUC__)
559 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, (LARGE_INTEGER
)0LL);
563 const LARGE_INTEGER dummy
=
567 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
570 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
571 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
572 if (!NT_SUCCESS(Status
))
574 DPRINT1("MM: Failed to write core dump header\n.");
577 NextOffset
+= PAGE_SIZE
;
582 /* Write out the contents of physical memory. */
583 if (MmCoreDumpType
== MM_CORE_DUMP_TYPE_FULL
)
585 for (i
= 0; i
< MmStats
.NrTotalPages
; i
++)
588 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame
,
592 #if defined(__GNUC__)
594 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
,
595 (LARGE_INTEGER
)NextOffset
);
600 dummy
.QuadPart
= NextOffset
;
601 DiskOffset
= MmGetOffsetPageFile(RetrievalPointers
, dummy
);
604 DiskOffset
.QuadPart
+= MmCoreDumpLcnMapping
.LcnDiskOffset
.QuadPart
;
605 Status
= MmCoreDumpFunctions
->DumpWrite(DiskOffset
, Mdl
);
606 MmRawDeleteVirtualMapping(MmCoreDumpPageFrame
);
607 if (!NT_SUCCESS(Status
))
609 DPRINT1("MM: Failed to write page to core dump.\n");
612 if ((i
% ((1024*1024) / PAGE_SIZE
)) == 0)
614 DbgPrint("\b\b%.2d", i
/ ((1024*1024)/PAGE_SIZE
));
616 NextOffset
+= PAGE_SIZE
;
621 MmCoreDumpFunctions
->DumpFinish();
622 return(STATUS_SUCCESS
);
626 MmInitializeCrashDump(HANDLE PageFileHandle
, ULONG PageFileNum
)
628 PFILE_OBJECT PageFile
;
629 PDEVICE_OBJECT PageFileDevice
;
633 IO_STATUS_BLOCK Iosb
;
634 UNICODE_STRING DiskDumpName
;
635 ANSI_STRING ProcName
;
636 PIO_STACK_LOCATION StackPtr
;
637 PMODULE_OBJECT ModuleObject
;
639 Status
= ZwFsControlFile(PageFileHandle
,
644 FSCTL_ROS_QUERY_LCN_MAPPING
,
647 &MmCoreDumpLcnMapping
,
648 sizeof(ROS_QUERY_LCN_MAPPING
));
649 if (!NT_SUCCESS(Status
) ||
650 Iosb
.Information
!= sizeof(ROS_QUERY_LCN_MAPPING
))
655 /* Get the underlying storage device. */
657 ObReferenceObjectByHandle(PageFileHandle
,
663 if (!NT_SUCCESS(Status
))
668 PageFileDevice
= PageFile
->Vpb
->RealDevice
;
670 /* Get the dump pointers. */
671 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
672 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS
,
677 sizeof(MmCoreDumpPointers
),
683 ObDereferenceObject(PageFile
);
684 return(STATUS_NO_MEMORY
);// tMk - is this correct return code ???
687 StackPtr
= IoGetNextIrpStackLocation(Irp
);
688 StackPtr
->FileObject
= PageFile
;
689 StackPtr
->DeviceObject
= PageFileDevice
;
690 StackPtr
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
691 StackPtr
->Parameters
.DeviceIoControl
.OutputBufferLength
= sizeof(MmCoreDumpPointers
);
693 Status
= IoCallDriver(PageFileDevice
,Irp
);
694 if (Status
== STATUS_PENDING
)
696 Status
= KeWaitForSingleObject(&Event
,
702 if (Status
!= STATUS_SUCCESS
||
703 Iosb
.Information
!= sizeof(MmCoreDumpPointers
))
705 ObDereferenceObject(PageFile
);
709 /* Load the diskdump driver. */
710 RtlRosInitUnicodeStringFromLiteral(&DiskDumpName
, L
"DiskDump");
711 ModuleObject
= LdrGetModuleObject(&DiskDumpName
);
712 if (ModuleObject
== NULL
)
714 return(STATUS_OBJECT_NAME_NOT_FOUND
);
716 RtlInitAnsiString(&ProcName
, "DiskDumpFunctions");
717 Status
= LdrGetProcedureAddress(ModuleObject
->Base
,
720 (PVOID
*)&MmCoreDumpFunctions
);
721 if (!NT_SUCCESS(Status
))
723 ObDereferenceObject(PageFile
);
727 /* Prepare for disk dumping. */
728 Status
= MmCoreDumpFunctions
->DumpPrepare(PageFileDevice
,
729 &MmCoreDumpPointers
);
730 if (!NT_SUCCESS(Status
))
732 ObDereferenceObject(PageFile
);
736 MmCoreDumpPageFile
= PageFileNum
;
737 ObDereferenceObject(PageFile
);
738 return(STATUS_SUCCESS
);
742 NtCreatePagingFile(IN PUNICODE_STRING FileName
,
743 IN PLARGE_INTEGER InitialSize
,
744 IN PLARGE_INTEGER MaximumSize
,
748 OBJECT_ATTRIBUTES ObjectAttributes
;
750 IO_STATUS_BLOCK IoStatus
;
751 PFILE_OBJECT FileObject
;
752 PPAGINGFILE PagingFile
;
755 FILE_FS_SIZE_INFORMATION FsSizeInformation
;
756 PRETRIEVEL_DESCRIPTOR_LIST RetDescList
;
757 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList
;
759 ULONG BytesPerAllocationUnit
;
766 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
767 FileName
, InitialSize
->QuadPart
);
769 if (MiPagingFileCount
>= MAX_PAGING_FILES
)
771 return(STATUS_TOO_MANY_PAGING_FILES
);
774 InitializeObjectAttributes(&ObjectAttributes
,
780 Status
= IoCreateFile(&FileHandle
,
788 FILE_SYNCHRONOUS_IO_NONALERT
,
793 SL_OPEN_PAGING_FILE
);
794 if (!NT_SUCCESS(Status
))
799 Status
= NtQueryVolumeInformationFile(FileHandle
,
802 sizeof(FILE_FS_SIZE_INFORMATION
),
803 FileFsSizeInformation
);
804 if (!NT_SUCCESS(Status
))
810 BytesPerAllocationUnit
= FsSizeInformation
.SectorsPerAllocationUnit
* FsSizeInformation
.BytesPerSector
;
811 if (BytesPerAllocationUnit
% PAGE_SIZE
)
814 return STATUS_UNSUCCESSFUL
;
817 Status
= NtSetInformationFile(FileHandle
,
820 sizeof(LARGE_INTEGER
),
821 FileAllocationInformation
);
822 if (!NT_SUCCESS(Status
))
828 Status
= ObReferenceObjectByHandle(FileHandle
,
834 if (!NT_SUCCESS(Status
))
840 CurrentRetDescList
= RetDescList
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
842 if (CurrentRetDescList
== NULL
)
844 ObDereferenceObject(FileObject
);
846 return(STATUS_NO_MEMORY
);
849 #if defined(__GNUC__)
857 MaxVcn
= (ULONG
)((InitialSize
->QuadPart
+ BytesPerAllocationUnit
- 1) / BytesPerAllocationUnit
);
860 Status
= NtFsControlFile(FileHandle
,
865 FSCTL_GET_RETRIEVAL_POINTERS
,
867 sizeof(LARGE_INTEGER
),
868 &CurrentRetDescList
->RetrievalPointers
,
869 sizeof(GET_RETRIEVAL_DESCRIPTOR
) + PAIRS_PER_RUN
* sizeof(MAPPING_PAIR
));
870 if (!NT_SUCCESS(Status
))
874 CurrentRetDescList
= RetDescList
;
875 RetDescList
= RetDescList
->Next
;
876 ExFreePool(CurrentRetDescList
);
878 ObDereferenceObject(FileObject
);
882 ExtentCount
+= CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
;
883 if ((ULONG
)CurrentRetDescList
->RetrievalPointers
.Pair
[CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
-1].Vcn
< MaxVcn
)
885 CurrentRetDescList
->Next
= MmAllocRetrievelDescriptorList(PAIRS_PER_RUN
);
886 if (CurrentRetDescList
->Next
== NULL
)
890 CurrentRetDescList
= RetDescList
;
891 RetDescList
= RetDescList
->Next
;
892 ExFreePool(CurrentRetDescList
);
894 ObDereferenceObject(FileObject
);
896 return(STATUS_NO_MEMORY
);
898 Vcn
.QuadPart
= CurrentRetDescList
->RetrievalPointers
.Pair
[CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
-1].Vcn
;
899 CurrentRetDescList
= CurrentRetDescList
->Next
;
907 PagingFile
= ExAllocatePool(NonPagedPool
, sizeof(*PagingFile
));
908 if (PagingFile
== NULL
)
912 CurrentRetDescList
= RetDescList
;
913 RetDescList
= RetDescList
->Next
;
914 ExFreePool(CurrentRetDescList
);
916 ObDereferenceObject(FileObject
);
918 return(STATUS_NO_MEMORY
);
921 RtlZeroMemory(PagingFile
, sizeof(*PagingFile
));
923 PagingFile
->FileObject
= FileObject
;
924 PagingFile
->MaximumSize
.QuadPart
= MaximumSize
->QuadPart
;
925 PagingFile
->CurrentSize
.QuadPart
= InitialSize
->QuadPart
;
926 PagingFile
->FreePages
= (ULONG
)(InitialSize
->QuadPart
/ PAGE_SIZE
);
927 PagingFile
->UsedPages
= 0;
928 KeInitializeSpinLock(&PagingFile
->AllocMapLock
);
930 AllocMapSize
= (PagingFile
->FreePages
/ 32) + 1;
931 PagingFile
->AllocMap
= ExAllocatePool(NonPagedPool
,
932 AllocMapSize
* sizeof(ULONG
));
933 PagingFile
->AllocMapSize
= AllocMapSize
;
935 if (PagingFile
->AllocMap
== NULL
)
939 CurrentRetDescList
= RetDescList
;
940 RetDescList
= RetDescList
->Next
;
941 ExFreePool(CurrentRetDescList
);
943 ExFreePool(PagingFile
);
944 ObDereferenceObject(FileObject
);
946 return(STATUS_NO_MEMORY
);
948 DPRINT("ExtentCount: %d\n", ExtentCount
);
949 Size
= sizeof(GET_RETRIEVAL_DESCRIPTOR
) + ExtentCount
* sizeof(MAPPING_PAIR
);
950 PagingFile
->RetrievalPointers
= ExAllocatePool(NonPagedPool
, Size
);
951 if (PagingFile
->RetrievalPointers
== NULL
)
955 CurrentRetDescList
= RetDescList
;
956 RetDescList
= RetDescList
->Next
;
957 ExFreePool(CurrentRetDescList
);
959 ExFreePool(PagingFile
->AllocMap
);
960 ExFreePool(PagingFile
);
961 ObDereferenceObject(FileObject
);
963 return(STATUS_NO_MEMORY
);
966 RtlZeroMemory(PagingFile
->AllocMap
, AllocMapSize
* sizeof(ULONG
));
967 RtlZeroMemory(PagingFile
->RetrievalPointers
, Size
);
970 PagingFile
->RetrievalPointers
->NumberOfPairs
= ExtentCount
;
971 PagingFile
->RetrievalPointers
->StartVcn
= RetDescList
->RetrievalPointers
.StartVcn
;
972 CurrentRetDescList
= RetDescList
;
973 while (CurrentRetDescList
)
975 memcpy(&PagingFile
->RetrievalPointers
->Pair
[Count
],
976 CurrentRetDescList
->RetrievalPointers
.Pair
,
977 CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
* sizeof(MAPPING_PAIR
));
978 Count
+= CurrentRetDescList
->RetrievalPointers
.NumberOfPairs
;
979 RetDescList
= CurrentRetDescList
;
980 CurrentRetDescList
= CurrentRetDescList
->Next
;
981 ExFreePool(RetDescList
);
984 if (PagingFile
->RetrievalPointers
->NumberOfPairs
!= ExtentCount
||
985 (ULONG
)PagingFile
->RetrievalPointers
->Pair
[ExtentCount
- 1].Vcn
!= MaxVcn
)
987 ExFreePool(PagingFile
->RetrievalPointers
);
988 ExFreePool(PagingFile
->AllocMap
);
989 ExFreePool(PagingFile
);
990 ObDereferenceObject(FileObject
);
992 return(STATUS_UNSUCCESSFUL
);
996 * Change the entries from lcn's to volume offset's.
998 PagingFile
->RetrievalPointers
->StartVcn
*= BytesPerAllocationUnit
;
999 for (i
= 0; i
< ExtentCount
; i
++)
1001 PagingFile
->RetrievalPointers
->Pair
[i
].Lcn
*= BytesPerAllocationUnit
;
1002 PagingFile
->RetrievalPointers
->Pair
[i
].Vcn
*= BytesPerAllocationUnit
;
1005 KeAcquireSpinLock(&PagingFileListLock
, &oldIrql
);
1006 for (i
= 0; i
< MAX_PAGING_FILES
; i
++)
1008 if (PagingFileList
[i
] == NULL
)
1010 PagingFileList
[i
] = PagingFile
;
1014 MiFreeSwapPages
= MiFreeSwapPages
+ PagingFile
->FreePages
;
1015 MiPagingFileCount
++;
1016 KeReleaseSpinLock(&PagingFileListLock
, oldIrql
);
1018 /* Check whether this pagefile can be a crash dump target. */
1019 if (MmCoreDumpType
!= MM_CORE_DUMP_TYPE_NONE
&&
1020 PagingFile
->CurrentSize
.QuadPart
>= MmCoreDumpSize
&&
1021 MmCoreDumpPageFile
== 0xFFFFFFFF)
1023 MmInitializeCrashDump(FileHandle
, i
);
1025 NtClose(FileHandle
);
1027 MmSwapSpaceMessage
= FALSE
;
1029 return(STATUS_SUCCESS
);